]> git.mxchange.org Git - flightgear.git/blob - src/Main/fg_init.cxx
Added simple proof-of-concept support for running PSL scripts from
[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  - curt@infoplane.com
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 #ifdef HAVE_WINDOWS_H
35 #  include <windows.h>
36 #endif
37
38 #include GLUT_H
39
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>             // strcmp()
43
44
45 #if defined( unix ) || defined( __CYGWIN__ )
46 #  include <unistd.h>           // for gethostname()
47 #endif
48
49 // work around a stdc++ lib bug in some versions of linux, but doesn't
50 // seem to hurt to have this here for all versions of Linux.
51 #ifdef linux
52 #  define _G_NO_EXTERN_TEMPLATES
53 #endif
54
55 #include <simgear/compiler.h>
56 #include <simgear/misc/exception.hxx>
57
58 #include STL_STRING
59
60 #include <simgear/constants.h>
61 #include <simgear/debug/logstream.hxx>
62 #include <simgear/math/point3d.hxx>
63 #include <simgear/math/polar3d.hxx>
64 #include <simgear/math/sg_geodesy.hxx>
65 #include <simgear/misc/sg_path.hxx>
66 #ifdef FG_USE_CLOUDS_3D
67 #  include <simgear/sky/clouds3d/SkySceneLoader.hpp>
68 #  include <simgear/sky/clouds3d/SkyUtil.hpp>
69 #endif
70 #include <simgear/timing/sg_time.hxx>
71 #include <simgear/timing/lowleveltime.h>
72
73 #include <Aircraft/aircraft.hxx>
74 #include <FDM/UIUCModel/uiuc_aircraftdir.h>
75 #include <Airports/runways.hxx>
76 #include <Airports/simple.hxx>
77 #include <ATC/ATCdisplay.hxx>
78 #include <ATC/ATCmgr.hxx>
79 #include <ATC/atislist.hxx>
80 #include <ATC/towerlist.hxx>
81 #include <ATC/approachlist.hxx>
82 #include <ATC/AIMgr.hxx>
83 #include <Autopilot/auto_gui.hxx>
84 #include <Autopilot/newauto.hxx>
85 #include <Cockpit/cockpit.hxx>
86 #include <Cockpit/radiostack.hxx>
87 #include <Cockpit/steam.hxx>
88 #include <Cockpit/panel.hxx>
89 #include <Cockpit/panel_io.hxx>
90 #include <FDM/ADA.hxx>
91 #include <FDM/Balloon.h>
92 #include <FDM/ExternalNet/ExternalNet.hxx>
93 #include <FDM/JSBSim/JSBSim.hxx>
94 #include <FDM/LaRCsim.hxx>
95 #include <FDM/MagicCarpet.hxx>
96 #include <FDM/UFO.hxx>
97 #include <FDM/NullFDM.hxx>
98 #include <FDM/YASim/YASim.hxx>
99 #include <GUI/new_gui.hxx>
100 #include <Include/general.hxx>
101 #include <Input/input.hxx>
102 #include <Instrumentation/instrument_mgr.hxx>
103 // #include <Joystick/joystick.hxx>
104 #include <Objects/matlib.hxx>
105 #include <Model/acmodel.hxx>
106 #include <Navaids/fixlist.hxx>
107 #include <Navaids/ilslist.hxx>
108 #include <Navaids/mkrbeacons.hxx>
109 #include <Navaids/navlist.hxx>
110 #include <Scenery/scenery.hxx>
111 #include <Scenery/tilemgr.hxx>
112 #include <Scripting/scriptmgr.hxx>
113 #include <Sound/fg_fx.hxx>
114 #include <Sound/soundmgr.hxx>
115 #include <Systems/system_mgr.hxx>
116 #include <Time/FGEventMgr.hxx>
117 #include <Time/light.hxx>
118 #include <Time/sunpos.hxx>
119 #include <Time/moonpos.hxx>
120 #include <Time/tmp.hxx>
121
122 #ifdef FG_WEATHERCM
123 #  include <WeatherCM/FGLocalWeatherDatabase.h>
124 #else
125 #  include <Environment/environment_mgr.hxx>
126 #endif
127
128 #include "fg_init.hxx"
129 #include "fg_io.hxx"
130 #include "fg_commands.hxx"
131 #include "fg_props.hxx"
132 #include "options.hxx"
133 #include "globals.hxx"
134 #include "logger.hxx"
135 #include "viewmgr.hxx"
136
137 #if defined(FX) && defined(XMESA)
138 #include <GL/xmesa.h>
139 #endif
140
141 SG_USING_STD(string);
142
143 extern const char *default_root;
144
145 #ifdef FG_USE_CLOUDS_3D
146   SkySceneLoader *sgCloud3d;
147 #endif
148
149
150 // Scan the command line options for the specified option and return
151 // the value.
152 static string fgScanForOption( const string& option, int argc, char **argv ) {
153     int i = 1;
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
218 // Read in configuration (files and command line options) but only set
219 // fg_root
220 bool fgInitFGRoot ( int argc, char **argv ) {
221     string root;
222     char* envp;
223
224     // First parse command line options looking for --fg-root=, this
225     // will override anything specified in a config file
226     root = fgScanForOption( "--fg-root=", argc, argv);
227
228 #if defined( unix ) || defined( __CYGWIN__ )
229     // Next check home directory for .fgfsrc.hostname file
230     if ( root.empty() ) {
231         envp = ::getenv( "HOME" );
232         if ( envp != NULL ) {
233             SGPath config( envp );
234             config.append( ".fgfsrc" );
235             char name[256];
236             gethostname( name, 256 );
237             config.concat( "." );
238             config.concat( name );
239             root = fgScanForOption( "--fg-root=", config.str() );
240         }
241     }
242 #endif
243
244     // Next check home directory for .fgfsrc file
245     if ( root.empty() ) {
246         envp = ::getenv( "HOME" );
247         if ( envp != NULL ) {
248             SGPath config( envp );
249             config.append( ".fgfsrc" );
250             root = fgScanForOption( "--fg-root=", config.str() );
251         }
252     }
253     
254     // Next check if fg-root is set as an env variable
255     if ( root.empty() ) {
256         envp = ::getenv( "FG_ROOT" );
257         if ( envp != NULL ) {
258             root = envp;
259         }
260     }
261
262     // Otherwise, default to a random compiled-in location if we can't
263     // find fg-root any other way.
264     if ( root.empty() ) {
265 #if defined( __CYGWIN__ )
266         root = "/FlightGear";
267 #elif defined( WIN32 )
268         root = "\\FlightGear";
269 #elif defined( macintosh )
270         root = "";
271 #else
272         root = PKGLIBDIR;
273 #endif
274     }
275
276     SG_LOG(SG_INPUT, SG_INFO, "fg_root = " << root );
277     globals->set_fg_root(root);
278
279     return true;
280 }
281
282
283 // Read in configuration (files and command line options) but only set
284 // aircraft
285 bool fgInitFGAircraft ( int argc, char **argv ) {
286     string aircraft;
287     char* envp;
288
289     // First parse command line options looking for --aircraft=, this
290     // will override anything specified in a config file
291     aircraft = fgScanForOption( "--aircraft=", argc, argv );
292
293 #if defined( unix ) || defined( __CYGWIN__ )
294     // Next check home directory for .fgfsrc.hostname file
295     if ( aircraft.empty() ) {
296         envp = ::getenv( "HOME" );
297         if ( envp != NULL ) {
298             SGPath config( envp );
299             config.append( ".fgfsrc" );
300             char name[256];
301             gethostname( name, 256 );
302             config.concat( "." );
303             config.concat( name );
304             aircraft = fgScanForOption( "--aircraft=", config.str() );
305         }
306     }
307 #endif
308
309     // Next check home directory for .fgfsrc file
310     if ( aircraft.empty() ) {
311         envp = ::getenv( "HOME" );
312         if ( envp != NULL ) {
313             SGPath config( envp );
314             config.append( ".fgfsrc" );
315             aircraft = fgScanForOption( "--aircraft=", config.str() );
316         }
317     }
318
319     // if an aircraft was specified, set the property name
320     if ( !aircraft.empty() ) {
321         SG_LOG(SG_INPUT, SG_INFO, "aircraft = " << aircraft );
322         fgSetString("/sim/aircraft", aircraft.c_str() );
323     } else {
324         SG_LOG(SG_INPUT, SG_INFO, "No user specified aircraft, using default" );
325     }
326
327     return true;
328 }
329
330
331 // Return the current base package version
332 string fgBasePackageVersion() {
333     SGPath base_path( globals->get_fg_root() );
334     base_path.append("version");
335
336     sg_gzifstream in( base_path.str() );
337     if ( !in.is_open() ) {
338         SGPath old_path( globals->get_fg_root() );
339         old_path.append( "Thanks" );
340         sg_gzifstream old( old_path.str() );
341         if ( !old.is_open() ) {
342             return "[none]";
343         } else {
344             return "[old version]";
345         }
346     }
347
348     string version;
349     in >> version;
350
351     return version;
352 }
353
354
355 // Initialize the localization
356 SGPropertyNode *fgInitLocale(const char *language) {
357    SGPropertyNode *c_node = NULL, *d_node = NULL;
358    SGPropertyNode *intl = fgGetNode("/sim/intl");
359
360    SG_LOG(SG_GENERAL, SG_INFO, "Selecting language: " << language );
361
362    // localization not defined
363    if (!intl)
364       return NULL;
365
366    //
367    // Select the proper language from the list
368    //
369    vector<SGPropertyNode_ptr> locale = intl->getChildren("locale");
370    for (unsigned int i = 0; i < locale.size(); i++) {
371
372       vector<SGPropertyNode_ptr> lang = locale[i]->getChildren("lang");
373       for (unsigned int j = 0; j < lang.size(); j++) {
374
375          if (!strcmp(lang[j]->getStringValue(), language)) {
376             c_node = locale[i];
377             break;
378          }
379       }
380    }
381
382
383    // Get the defaults
384    d_node = intl->getChild("locale");
385    if (!c_node)
386       c_node = d_node;
387
388    // Check for localized font
389    SGPropertyNode *font_n = c_node->getNode("font", true);
390    if ( !strcmp(font_n->getStringValue(), "") )
391       font_n->setStringValue(d_node->getStringValue("font", "typewriter.txf"));
392
393
394    //
395    // Load the default strings
396    //
397    SGPath d_path( globals->get_fg_root() );
398
399    const char *d_path_str = d_node->getStringValue("strings");
400    if (!d_path_str) {
401       SG_LOG(SG_GENERAL, SG_ALERT, "Incorrect path in configuration file.");
402       return NULL;
403    }
404
405    d_path.append(d_path_str);
406    SG_LOG(SG_GENERAL, SG_INFO, "Reading localized strings from "
407                                   << d_path.str());
408
409    SGPropertyNode *strings = c_node->getNode("strings");
410    try {
411       readProperties(d_path.str(), strings);
412    } catch (const sg_exception &e) {
413       SG_LOG(SG_GENERAL, SG_ALERT, "Unable to read the localized strings");
414       return NULL;
415    }
416
417    //
418    // Load the language specific strings
419    //
420    if (c_node != d_node) {
421       SGPath c_path( globals->get_fg_root() );
422
423       const char *c_path_str = c_node->getStringValue("strings");
424       if (!c_path_str) {
425          SG_LOG(SG_GENERAL, SG_ALERT, "Incorrect path in configuration file.");
426          return NULL;
427       }
428
429       c_path.append(c_path_str);
430       SG_LOG(SG_GENERAL, SG_INFO, "Reading localized strings from "
431                                      << c_path.str());
432
433       try {
434          readProperties(c_path.str(), strings);
435       } catch (const sg_exception &e) {
436          SG_LOG(SG_GENERAL, SG_ALERT, "Unable to read the localized strings");
437          return NULL;
438       }
439    }
440
441    return c_node;
442 }
443
444
445
446 // Initialize the localization routines
447 bool fgDetectLanguage() {
448     char *language = ::getenv("LANG");
449
450     if (language == NULL) {
451         SG_LOG(SG_GENERAL, SG_INFO, "Unable to detect the language" );
452         language = "C";
453     }
454
455     SGPropertyNode *locale = fgInitLocale(language);
456     if (!locale) {
457        cerr << "No internationalization settings specified in preferences.xml"
458             << endl;
459
460        return false;
461     }
462
463     globals->set_locale( locale );
464
465     return true;
466 }
467
468 // Attempt to locate and parse the various non-XML config files in order
469 // from least precidence to greatest precidence
470 static void
471 do_options (int argc, char ** argv)
472 {
473     // Check for $fg_root/system.fgfsrc
474     SGPath config( globals->get_fg_root() );
475     config.append( "system.fgfsrc" );
476     fgParseOptions(config.str());
477
478 #if defined( unix ) || defined( __CYGWIN__ )
479     char name[256];
480     // Check for $fg_root/system.fgfsrc.hostname
481     gethostname( name, 256 );
482     config.concat( "." );
483     config.concat( name );
484     fgParseOptions(config.str());
485 #endif
486
487     // Check for ~/.fgfsrc
488     char* envp = ::getenv( "HOME" );
489     if ( envp != NULL ) {
490         config.set( envp );
491         config.append( ".fgfsrc" );
492         fgParseOptions(config.str());
493     }
494
495 #if defined( unix ) || defined( __CYGWIN__ )
496     // Check for ~/.fgfsrc.hostname
497     gethostname( name, 256 );
498     config.concat( "." );
499     config.concat( name );
500     fgParseOptions(config.str());
501 #endif
502
503     // Parse remaining command line options
504     // These will override anything specified in a config file
505     fgParseArgs(argc, argv);
506 }
507
508
509 // Read in configuration (file and command line)
510 bool fgInitConfig ( int argc, char **argv ) {
511
512     // First, set some sane default values
513     fgSetDefaults();
514
515     // Read global preferences from $FG_ROOT/preferences.xml
516     SG_LOG(SG_INPUT, SG_INFO, "Reading global preferences");
517     fgLoadProps("preferences.xml", globals->get_props());
518     SG_LOG(SG_INPUT, SG_INFO, "Finished Reading global preferences");
519
520     // Detect the required language as early as possible
521     if ( !fgDetectLanguage() ) {
522         return false;
523     }
524
525     // Scan user config files and command line for a specified aircraft.
526     fgInitFGAircraft(argc, argv);
527
528     string aircraft = fgGetString("/sim/aircraft", "");
529     if ( aircraft.size() > 0 ) {
530         SGPath aircraft_path(globals->get_fg_root());
531         aircraft_path.append("Aircraft");
532         aircraft_path.append(aircraft);
533         aircraft_path.concat("-set.xml");
534         SG_LOG(SG_INPUT, SG_INFO, "Reading default aircraft: " << aircraft
535                << " from " << aircraft_path.str());
536         try {
537             readProperties(aircraft_path.str(), globals->get_props());
538         } catch (const sg_exception &e) {
539             string message = "Error reading default aircraft: ";
540             message += e.getFormattedMessage();
541             SG_LOG(SG_INPUT, SG_ALERT, message);
542             exit(2);
543         }
544     } else {
545         SG_LOG(SG_INPUT, SG_ALERT, "No default aircraft specified");
546     }
547
548     // parse options after loading aircraft to ensure any user
549     // overrides of defaults are honored.
550     do_options(argc, argv);
551
552     return true;
553 }
554
555
556 // find basic airport location info from airport database
557 bool fgFindAirportID( const string& id, FGAirport *a ) {
558     if ( id.length() ) {
559         SGPath path( globals->get_fg_root() );
560         path.append( "Airports" );
561         path.append( "simple.mk4" );
562         FGAirports airports( path.c_str() );
563
564         SG_LOG( SG_GENERAL, SG_INFO, "Searching for airport code = " << id );
565
566         if ( ! airports.search( id, a ) ) {
567             SG_LOG( SG_GENERAL, SG_ALERT,
568                     "Failed to find " << id << " in " << path.str() );
569             return false;
570         }
571     } else {
572         return false;
573     }
574
575     SG_LOG( SG_GENERAL, SG_INFO,
576             "Position for " << id << " is ("
577             << a->longitude << ", "
578             << a->latitude << ")" );
579
580     return true;
581 }
582
583
584 // get airport elevation
585 static double fgGetAirportElev( const string& id ) {
586     FGAirport a;
587     // double lon, lat;
588
589     SG_LOG( SG_GENERAL, SG_INFO,
590             "Finding elevation for airport: " << id );
591
592     if ( fgFindAirportID( id, &a ) ) {
593         return a.elevation;
594     } else {
595         return -9999.0;
596     }
597 }
598
599
600 // Preset lon/lat given an airport id
601 static bool fgSetPosFromAirportID( const string& id ) {
602     FGAirport a;
603     // double lon, lat;
604
605     SG_LOG( SG_GENERAL, SG_INFO,
606             "Attempting to set starting position from airport code " << id );
607
608     if ( fgFindAirportID( id, &a ) ) {
609         // presets
610         fgSetDouble("/sim/presets/longitude-deg", a.longitude );
611         fgSetDouble("/sim/presets/latitude-deg", a.latitude );
612
613         // other code depends on the actual postition being set so set
614         // that as well
615         fgSetDouble("/position/longitude-deg", a.longitude );
616         fgSetDouble("/position/latitude-deg", a.latitude );
617
618         SG_LOG( SG_GENERAL, SG_INFO,
619                 "Position for " << id << " is (" << a.longitude
620                 << ", " << a.latitude << ")" );
621
622         return true;
623     } else {
624         return false;
625     }
626 }
627
628
629 // Set current tower position lon/lat given an airport id
630 static bool fgSetTowerPosFromAirportID( const string& id, double hdg ) {
631     FGAirport a;
632     // tower height hard coded for now...
633     float towerheight=50.0f;
634
635     // make a little off the heading for 1 runway airports...
636     float fudge_lon = fabs(sin(hdg)) * .003f;
637     float fudge_lat = .003f - fudge_lon;
638
639     if ( fgFindAirportID( id, &a ) ) {
640         fgSetDouble("/sim/tower/longitude-deg",  a.longitude + fudge_lon);
641         fgSetDouble("/sim/tower/latitude-deg",  a.latitude + fudge_lat);
642         fgSetDouble("/sim/tower/altitude-ft", a.elevation + towerheight);
643         return true;
644     } else {
645         return false;
646     }
647
648 }
649
650
651 // Set current_options lon/lat given an airport id and heading (degrees)
652 static bool fgSetPosFromAirportIDandHdg( const string& id, double tgt_hdg ) {
653     FGRunway r;
654     FGRunway found_r;
655     double found_dir = 0.0;
656
657     if ( id.length() ) {
658         // set initial position from runway and heading
659
660         SGPath path( globals->get_fg_root() );
661         path.append( "Airports" );
662         path.append( "runways.mk4" );
663         FGRunways runways( path.c_str() );
664
665         SG_LOG( SG_GENERAL, SG_INFO,
666                 "Attempting to set starting position from runway code "
667                 << id << " heading " << tgt_hdg );
668
669         if ( ! runways.search( id, &r ) ) {
670             SG_LOG( SG_GENERAL, SG_ALERT,
671                     "Failed to find " << id << " in database." );
672             return false;
673         }
674
675         double diff;
676         double min_diff = 360.0;
677
678         while ( r.id == id ) {
679             // forward direction
680             diff = tgt_hdg - r.heading;
681             while ( diff < -180.0 ) { diff += 360.0; }
682             while ( diff >  180.0 ) { diff -= 360.0; }
683             diff = fabs(diff);
684             SG_LOG( SG_GENERAL, SG_INFO,
685                     "Runway " << r.rwy_no << " heading = " << r.heading <<
686                     " diff = " << diff );
687             if ( diff < min_diff ) {
688                 min_diff = diff;
689                 found_r = r;
690                 found_dir = 0;
691             }
692
693             // reverse direction
694             diff = tgt_hdg - r.heading - 180.0;
695             while ( diff < -180.0 ) { diff += 360.0; }
696             while ( diff >  180.0 ) { diff -= 360.0; }
697             diff = fabs(diff);
698             SG_LOG( SG_GENERAL, SG_INFO,
699                     "Runway -" << r.rwy_no << " heading = " <<
700                     r.heading + 180.0 <<
701                     " diff = " << diff );
702             if ( diff < min_diff ) {
703                 min_diff = diff;
704                 found_r = r;
705                 found_dir = 180.0;
706             }
707
708             runways.next( &r );
709         }
710
711         SG_LOG( SG_GENERAL, SG_INFO, "closest runway = " << found_r.rwy_no
712                 << " + " << found_dir );
713
714     } else {
715         return false;
716     }
717
718     double heading = found_r.heading + found_dir;
719     while ( heading >= 360.0 ) { heading -= 360.0; }
720
721     double lat2, lon2, az2;
722     double azimuth = found_r.heading + found_dir + 180.0;
723     while ( azimuth >= 360.0 ) { azimuth -= 360.0; }
724
725     SG_LOG( SG_GENERAL, SG_INFO,
726             "runway =  " << found_r.lon << ", " << found_r.lat
727             << " length = " << found_r.length * SG_FEET_TO_METER * 0.5 
728             << " heading = " << azimuth );
729     
730     geo_direct_wgs_84 ( 0, found_r.lat, found_r.lon, 
731                         azimuth, found_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         }
742         while ( oaz >= 360.0 ) { oaz -= 360.0; }
743         geo_direct_wgs_84 ( 0, lat2, lon2, oaz, odist, &olat, &olon, &az2 );
744         lat2=olat;
745         lon2=olon;
746     }
747
748     // presets
749     fgSetDouble("/sim/presets/longitude-deg",  lon2 );
750     fgSetDouble("/sim/presets/latitude-deg",  lat2 );
751     fgSetDouble("/sim/presets/heading-deg", heading );
752
753     // other code depends on the actual values being set ...
754     fgSetDouble("/position/longitude-deg",  lon2 );
755     fgSetDouble("/position/latitude-deg",  lat2 );
756     fgSetDouble("/orientation/heading-deg", heading );
757
758     SG_LOG( SG_GENERAL, SG_INFO,
759             "Position for " << id << " is ("
760             << lon2 << ", "
761             << lat2 << ") new heading is "
762             << heading );
763
764     return true;
765 }
766
767
768 // Set current_options lon/lat given an airport id and heading (degrees)
769 static bool fgSetPosFromAirportIDandRwy( const string& id, const string& rwy ) {
770     FGRunway r;
771     FGRunway found_r;
772     double heading = 0.0;
773     string runway;
774     bool match = false;
775
776     // standardize input number
777     string tmp = rwy.substr(1, 1);
778     if ( tmp == "L" || tmp == "R" || tmp == "C" ) {
779         runway = "0";
780         runway += rwy;
781     } else {
782         runway = rwy;
783     }
784
785     if ( id.length() ) {
786         // set initial position from runway and heading
787
788         SGPath path( globals->get_fg_root() );
789         path.append( "Airports" );
790         path.append( "runways.mk4" );
791         FGRunways runways( path.c_str() );
792
793         SG_LOG( SG_GENERAL, SG_INFO,
794                 "Attempting to set starting position for "
795                 << id << ":" << runway );
796
797         if ( ! runways.search( id, &r ) ) {
798             SG_LOG( SG_GENERAL, SG_ALERT,
799                     "Failed to find " << id << " in database." );
800             return false;
801         }
802
803         while ( r.id == id ) {
804             // forward direction
805             if ( r.rwy_no == runway ) {
806                 found_r = r;
807                 heading = r.heading;
808                 match = true;
809                 SG_LOG( SG_GENERAL, SG_INFO,
810                         "Runway " << r.rwy_no << " heading = " << heading );
811             }
812
813             // calculate reciprocal runway number
814             string snum = r.rwy_no;
815             int len = snum.length();
816             string letter = "";
817             string rev_letter = "";
818             int i;
819             for ( i = 0; i < len; ++i ) {
820                 string tmp = snum.substr(i, 1);
821                 if ( tmp == "L" ) {
822                     letter = "L";
823                     rev_letter = "R";
824                 } else if ( tmp == "R" ) {
825                     letter = "R";
826                     rev_letter = "L";
827                 } else if ( tmp == "C" ) {
828                     letter == "C";
829                     rev_letter = "C";
830                 }
831             }
832             for ( i = 0; i < len; ++i ) {
833                 string tmp = snum.substr(i, 1);
834                 if ( tmp == "L" || tmp == "R" || tmp == "C" || tmp == " " ) {
835                     snum = snum.substr(0, i);
836                 }
837             }
838             SG_LOG(SG_GENERAL, SG_DEBUG, "Runway num = '" << snum << "'");
839             int num = atoi( snum.c_str() ) + 18;
840             while ( num > 36 ) { num -= 36; }
841             while ( num <= 0 ) { num += 36; }
842
843             char recip_no[10];
844             snprintf( recip_no, 10, "%02d%s", num, rev_letter.c_str() );
845
846             // reverse direction
847             if ( (string)recip_no == runway ) {
848                 found_r = r;
849                 heading = r.heading + 180;
850                 while ( heading > 360.0 ) { heading -= 360; }
851                 match = true;
852                 SG_LOG( SG_GENERAL, SG_INFO,
853                         "Runway " << r.rwy_no << " heading = " << heading );
854             }
855
856             runways.next( &r );
857         }
858     } else {
859         return false;
860     }
861
862     if ( match ) {
863         double lat2, lon2, az2;
864         double azimuth = heading + 180.0;
865         while ( azimuth >= 360.0 ) { azimuth -= 360.0; }
866
867         SG_LOG( SG_GENERAL, SG_INFO,
868                 "runway =  " << found_r.lon << ", " << found_r.lat
869                 << " length = " << found_r.length * SG_FEET_TO_METER * 0.5 
870                 << " heading = " << azimuth );
871     
872         geo_direct_wgs_84 ( 0, found_r.lat, found_r.lon, 
873                             azimuth,
874                             found_r.length * SG_FEET_TO_METER * 0.5 - 5.0,
875                             &lat2, &lon2, &az2 );
876
877         if ( fabs( fgGetDouble("/sim/presets/offset-distance") ) > SG_EPSILON )
878         {
879             double olat, olon;
880             double odist = fgGetDouble("/sim/presets/offset-distance");
881             odist *= SG_NM_TO_METER;
882             double oaz = azimuth;
883             if ( fabs(fgGetDouble("/sim/presets/offset-azimuth")) > SG_EPSILON )
884             {
885                 oaz = fgGetDouble("/sim/presets/offset-azimuth") + 180;
886             }
887             while ( oaz >= 360.0 ) { oaz -= 360.0; }
888             geo_direct_wgs_84 ( 0, lat2, lon2, oaz, odist, &olat, &olon, &az2 );
889             lat2=olat;
890             lon2=olon;
891         }
892
893         // presets
894         fgSetDouble("/sim/presets/longitude-deg",  lon2 );
895         fgSetDouble("/sim/presets/latitude-deg",  lat2 );
896         fgSetDouble("/sim/presets/heading-deg", heading );
897
898         // other code depends on the actual values being set ...
899         fgSetDouble("/position/longitude-deg",  lon2 );
900         fgSetDouble("/position/latitude-deg",  lat2 );
901         fgSetDouble("/orientation/heading-deg", heading );
902
903         SG_LOG( SG_GENERAL, SG_INFO,
904                 "Position for " << id << " is ("
905                 << lon2 << ", "
906                 << lat2 << ") new heading is "
907                 << heading );
908
909         return true;
910     } else {
911         return false;
912     }
913 }
914
915
916 static void fgSetDistOrAltFromGlideSlope() {
917     string apt_id = fgGetString("/sim/presets/airport-id");
918     double gs = fgGetDouble("/sim/presets/glideslope-deg")
919         * SG_DEGREES_TO_RADIANS ;
920     double od = fgGetDouble("/sim/presets/offset-distance");
921     double alt = fgGetDouble("/sim/presets/altitude-ft");
922
923     double apt_elev = 0.0;
924     if ( ! apt_id.empty() ) {
925         apt_elev = fgGetAirportElev( apt_id );
926         if ( apt_elev < -9990.0 ) {
927             apt_elev = 0.0;
928         }
929     } else {
930         apt_elev = 0.0;
931     }
932
933     if( fabs(gs) > 0.01 && fabs(od) > 0.1 && alt < -9990 ) {
934         // set altitude from glideslope and offset-distance
935         od *= SG_NM_TO_METER * SG_METER_TO_FEET;
936         alt = fabs(od*tan(gs)) + apt_elev;
937         fgSetDouble("/sim/presets/altitude-ft", alt);
938         fgSetBool("/sim/presets/onground", false);
939         SG_LOG( SG_GENERAL, SG_INFO, "Calculated altitude as: "
940                 << alt  << " ft" );
941     } else if( fabs(gs) > 0.01 && alt > 0 && fabs(od) < 0.1) {
942         // set offset-distance from glideslope and altitude
943         od  = (alt - apt_elev) / tan(gs);
944         od *= -1*SG_FEET_TO_METER * SG_METER_TO_NM;
945         fgSetDouble("/sim/presets/offset-distance", od);
946         fgSetBool("/sim/presets/onground", false);
947         SG_LOG( SG_GENERAL, SG_INFO, "Calculated offset distance as: " 
948                 << od  << " nm" );
949     } else if( fabs(gs) > 0.01 ) {
950         SG_LOG( SG_GENERAL, SG_ALERT,
951                 "Glideslope given but not altitude or offset-distance." );
952         SG_LOG( SG_GENERAL, SG_ALERT, "Resetting glideslope to zero" );
953         fgSetDouble("/sim/presets/glideslope-deg", 0);
954         fgSetBool("/sim/presets/onground", true);
955     }                              
956 }                       
957
958
959 // Set current_options lon/lat given an airport id and heading (degrees)
960 static bool fgSetPosFromNAV( const string& id, const double& freq ) {
961     FGNav nav;
962
963     // set initial position from runway and heading
964     if ( current_navlist->findByIdentAndFreq( id.c_str(), freq, &nav ) ) {
965         SG_LOG( SG_GENERAL, SG_INFO, "Attempting to set starting position for "
966                 << id << ":" << freq );
967
968         double lon = nav.get_lon();
969         double lat = nav.get_lat();
970
971         if ( fabs( fgGetDouble("/sim/presets/offset-distance") ) > SG_EPSILON )
972         {
973             double odist = fgGetDouble("/sim/presets/offset-distance")
974                 * SG_NM_TO_METER;
975             double oaz = fabs(fgGetDouble("/sim/presets/offset-azimuth"))
976                 + 180.0;
977             while ( oaz >= 360.0 ) { oaz -= 360.0; }
978             double olat, olon, az2;
979             geo_direct_wgs_84 ( 0, lat, lon, oaz, odist, &olat, &olon, &az2 );
980
981             lat = olat;
982             lon = olon;
983         }
984
985         // presets
986         fgSetDouble("/sim/presets/longitude-deg",  lon );
987         fgSetDouble("/sim/presets/latitude-deg",  lat );
988
989         // other code depends on the actual values being set ...
990         fgSetDouble("/position/longitude-deg",  lon );
991         fgSetDouble("/position/latitude-deg",  lat );
992         fgSetDouble("/orientation/heading-deg", 
993                     fgGetDouble("/sim/presets/heading-deg") );
994
995         SG_LOG( SG_GENERAL, SG_INFO,
996                 "Position for " << id << ":" << freq << " is ("
997                 << lon << ", "<< lat << ")" );
998
999         return true;
1000     } else {
1001         SG_LOG( SG_GENERAL, SG_ALERT, "Failed to locate NAV = "
1002                 << id << ":" << freq );
1003         return false;
1004     }
1005 }
1006
1007
1008 // Set current_options lon/lat given an airport id and heading (degrees)
1009 static bool fgSetPosFromFix( const string& id ) {
1010     FGFix fix;
1011
1012     // set initial position from runway and heading
1013     if ( current_fixlist->query( id.c_str(), &fix ) ) {
1014         SG_LOG( SG_GENERAL, SG_INFO, "Attempting to set starting position for "
1015                 << id );
1016
1017         double lon = fix.get_lon();
1018         double lat = fix.get_lat();
1019
1020         if ( fabs( fgGetDouble("/sim/presets/offset-distance") ) > SG_EPSILON )
1021         {
1022             double odist = fgGetDouble("/sim/presets/offset-distance")
1023                 * SG_NM_TO_METER;
1024             double oaz = fabs(fgGetDouble("/sim/presets/offset-azimuth"))
1025                 + 180.0;
1026             while ( oaz >= 360.0 ) { oaz -= 360.0; }
1027             double olat, olon, az2;
1028             geo_direct_wgs_84 ( 0, lat, lon, oaz, odist, &olat, &olon, &az2 );
1029
1030             lat = olat;
1031             lon = olon;
1032         }
1033
1034         // presets
1035         fgSetDouble("/sim/presets/longitude-deg",  lon );
1036         fgSetDouble("/sim/presets/latitude-deg",  lat );
1037
1038         // other code depends on the actual values being set ...
1039         fgSetDouble("/position/longitude-deg",  lon );
1040         fgSetDouble("/position/latitude-deg",  lat );
1041         fgSetDouble("/orientation/heading-deg", 
1042                     fgGetDouble("/sim/presets/heading-deg") );
1043
1044         SG_LOG( SG_GENERAL, SG_INFO,
1045                 "Position for " << id << " is ("
1046                 << lon << ", "<< lat << ")" );
1047
1048         return true;
1049     } else {
1050         SG_LOG( SG_GENERAL, SG_ALERT, "Failed to locate NAV = "
1051                 << id );
1052         return false;
1053     }
1054 }
1055
1056
1057 // Set the initial position based on presets (or defaults)
1058 bool fgInitPosition() {
1059     bool set_pos = false;
1060
1061     // If glideslope is specified, then calculate offset-distance or
1062     // altitude relative to glide slope if either of those was not
1063     // specified.
1064     fgSetDistOrAltFromGlideSlope();
1065
1066     // If we have an explicit, in-range lon/lat, don't change it, just use it.
1067     // If not, check for an airport-id and use that.
1068     // If not, default to the middle of the KSFO field.
1069     // The default values for lon/lat are deliberately out of range
1070     // so that the airport-id can take effect; valid lon/lat will
1071     // override airport-id, however.
1072     double lon_deg = fgGetDouble("/sim/presets/longitude-deg");
1073     double lat_deg = fgGetDouble("/sim/presets/latitude-deg");
1074     if ( lon_deg >= -180.0 && lon_deg <= 180.0
1075          && lat_deg >= -90.0 && lat_deg <= 90.0 )
1076     {
1077         set_pos = true;
1078     }
1079
1080     string apt = fgGetString("/sim/presets/airport-id");
1081     string rwy_no = fgGetString("/sim/presets/runway");
1082     double hdg = fgGetDouble("/sim/presets/heading-deg");
1083     string vor = fgGetString("/sim/presets/vor-id");
1084     double vor_freq = fgGetDouble("/sim/presets/vor-freq");
1085     string ndb = fgGetString("/sim/presets/ndb-id");
1086     double ndb_freq = fgGetDouble("/sim/presets/ndb-freq");
1087     string fix = fgGetString("/sim/presets/fix");
1088     if ( !set_pos && !apt.empty() && !rwy_no.empty() ) {
1089         // An airport + runway is requested
1090         if ( fgSetPosFromAirportIDandRwy( apt, rwy_no ) ) {
1091             // set position (a little off the heading for single
1092             // runway airports)
1093             fgSetTowerPosFromAirportID( apt, hdg );
1094
1095             set_pos = true;
1096         }
1097     }
1098     if ( !set_pos && !apt.empty() ) {
1099         // An airport is requested (find runway closest to hdg)
1100         if ( fgSetPosFromAirportIDandHdg( apt, hdg ) ) {
1101             // set position (a little off the heading for single
1102             // runway airports)
1103             fgSetTowerPosFromAirportID( apt, hdg );
1104
1105             set_pos = true;
1106         }
1107     }
1108     if ( !set_pos && !vor.empty() ) {
1109         // a VOR is requested
1110         if ( fgSetPosFromNAV( vor, vor_freq ) ) {
1111             if ( fgGetDouble("/sim/presets/altitude-ft") > -9990.0 ) {
1112                 fgSetBool("/sim/presets/onground", false);
1113             } else {
1114                 fgSetBool("/sim/presets/onground", true);
1115             }
1116             set_pos = true;
1117         }
1118     }
1119     if ( !set_pos && !ndb.empty() ) {
1120         // an NDB is requested
1121         if ( fgSetPosFromNAV( ndb, ndb_freq ) ) {
1122             if ( fgGetDouble("/sim/presets/altitude-ft") > -9990.0 ) {
1123                 fgSetBool("/sim/presets/onground", false);
1124             } else {
1125                 fgSetBool("/sim/presets/onground", true);
1126             }
1127             set_pos = true;
1128         }
1129     }
1130     if ( !set_pos && !fix.empty() ) {
1131         // a Fix is requested
1132         if ( fgSetPosFromFix( fix ) ) {
1133             if ( fgGetDouble("/sim/presets/altitude-ft") > -9990.0 ) {
1134                 fgSetBool("/sim/presets/onground", false);
1135             } else {
1136                 fgSetBool("/sim/presets/onground", true);
1137             }
1138             set_pos = true;
1139         }
1140     }
1141
1142     if ( !set_pos ) {
1143         // No lon/lat specified, no airport specified, default to
1144         // middle of KSFO field.
1145         fgSetDouble("/sim/presets/longitude-deg", -122.374843);
1146         fgSetDouble("/sim/presets/latitude-deg", 37.619002);
1147     }
1148
1149     fgSetDouble( "/position/longitude-deg",
1150                  fgGetDouble("/sim/presets/longitude-deg") );
1151     fgSetDouble( "/position/latitude-deg",
1152                  fgGetDouble("/sim/presets/latitude-deg") );
1153     fgSetDouble( "/orientation/heading-deg",
1154                  fgGetDouble("/sim/presets/heading-deg") );
1155
1156     return true;
1157 }
1158
1159
1160 // General house keeping initializations
1161 bool fgInitGeneral() {
1162     string root;
1163
1164 #if defined(FX) && defined(XMESA)
1165     char *mesa_win_state;
1166 #endif
1167
1168     SG_LOG( SG_GENERAL, SG_INFO, "General Initialization" );
1169     SG_LOG( SG_GENERAL, SG_INFO, "======= ==============" );
1170
1171     root = globals->get_fg_root();
1172     if ( ! root.length() ) {
1173         // No root path set? Then bail ...
1174         SG_LOG( SG_GENERAL, SG_ALERT,
1175                 "Cannot continue without a path to the base package "
1176                 << "being defined." );
1177         exit(-1);
1178     }
1179     SG_LOG( SG_GENERAL, SG_INFO, "FG_ROOT = " << '"' << root << '"' << endl );
1180
1181 #if defined(FX) && defined(XMESA)
1182     // initialize full screen flag
1183     globals->set_fullscreen(false);
1184     if ( strstr ( general.get_glRenderer(), "Glide" ) ) {
1185         // Test for the MESA_GLX_FX env variable
1186         if ( (mesa_win_state = getenv( "MESA_GLX_FX" )) != NULL) {
1187             // test if we are fullscreen mesa/glide
1188             if ( (mesa_win_state[0] == 'f') ||
1189                  (mesa_win_state[0] == 'F') ) {
1190                 globals->set_fullscreen(true);
1191             }
1192         }
1193     }
1194 #endif
1195
1196     return true;
1197 }
1198
1199
1200 // Initialize the flight model subsystem.  This just creates the
1201 // object.  The actual fdm initialization is delayed until we get a
1202 // proper scenery elevation hit.  This is checked for in main.cxx
1203
1204 void fgInitFDM() {
1205
1206     if ( cur_fdm_state ) {
1207         delete cur_fdm_state;
1208         cur_fdm_state = 0;
1209     }
1210
1211     double dt = 1.0 / fgGetInt("/sim/model-hz");
1212     aircraft_dir = fgGetString("/sim/aircraft-dir");
1213     const string &model = fgGetString("/sim/flight-model");
1214
1215     try {
1216         if ( model == "larcsim" ) {
1217             cur_fdm_state = new FGLaRCsim( dt );
1218         } else if ( model == "jsb" ) {
1219             cur_fdm_state = new FGJSBsim( dt );
1220         } else if ( model == "ada" ) {
1221             cur_fdm_state = new FGADA( dt );
1222         } else if ( model == "balloon" ) {
1223             cur_fdm_state = new FGBalloonSim( dt );
1224         } else if ( model == "magic" ) {
1225             cur_fdm_state = new FGMagicCarpet( dt );
1226         } else if ( model == "ufo" ) {
1227             cur_fdm_state = new FGUFO( dt );
1228         } else if ( model == "external" ) {
1229             // external is a synonym for "--fdm=null" and is
1230             // maintained here for backwards compatibility
1231             cur_fdm_state = new FGNullFDM( dt );
1232         } else if ( model.find("network") == 0 ) {
1233             string host = "localhost";
1234             int port1 = 5501;
1235             int port2 = 5502;
1236             int port3 = 5503;
1237             string net_options = model.substr(8);
1238             string::size_type begin, end;
1239             begin = 0;
1240             // host
1241             end = net_options.find( ",", begin );
1242             if ( end != string::npos ) {
1243                 host = net_options.substr(begin, end - begin);
1244                 begin = end + 1;
1245             }
1246             // port1
1247             end = net_options.find( ",", begin );
1248             if ( end != string::npos ) {
1249                 port1 = atoi( net_options.substr(begin, end - begin).c_str() );
1250                 begin = end + 1;
1251             }
1252             // port2
1253             end = net_options.find( ",", begin );
1254             if ( end != string::npos ) {
1255                 port2 = atoi( net_options.substr(begin, end - begin).c_str() );
1256                 begin = end + 1;
1257             }
1258             // port3
1259             end = net_options.find( ",", begin );
1260             if ( end != string::npos ) {
1261                 port3 = atoi( net_options.substr(begin, end - begin).c_str() );
1262                 begin = end + 1;
1263             }
1264             cur_fdm_state = new FGExternalNet( dt, host, port1, port2, port3 );
1265         } else if ( model == "null" ) {
1266             cur_fdm_state = new FGNullFDM( dt );
1267         } else if ( model == "yasim" ) {
1268             cur_fdm_state = new YASim( dt );
1269         } else {
1270             SG_LOG(SG_GENERAL, SG_ALERT,
1271                    "Unrecognized flight model '" << model
1272                    << "', cannot init flight dynamics model.");
1273             exit(-1);
1274         }
1275     } catch ( ... ) {
1276         SG_LOG(SG_GENERAL, SG_ALERT, "FlightGear aborting\n\n");
1277         exit(-1);
1278     }
1279 }
1280
1281 static void printMat(const sgVec4 *mat, char *name="")
1282 {
1283     int i;
1284     cout << name << endl;
1285     for(i=0; i<4; i++) {
1286         cout <<"  "<<mat[i][0]<<" "<<mat[i][1]<<" "<<mat[i][2]<<" "<<mat[i][3]<<endl;
1287     }
1288     cout << endl;
1289 }
1290
1291 // Initialize view parameters
1292 void fgInitView() {
1293   // force update of model so that viewer can get some data...
1294   globals->get_aircraft_model()->update(0);
1295   // run update for current view so that data is current...
1296   globals->get_viewmgr()->update(0);
1297
1298   printMat(globals->get_current_view()->get_VIEW(),"VIEW");
1299   printMat(globals->get_current_view()->get_UP(),"UP");
1300   // printMat(globals->get_current_view()->get_LOCAL(),"LOCAL");
1301   
1302 }
1303
1304
1305 SGTime *fgInitTime() {
1306     // Initialize time
1307     static const SGPropertyNode *longitude
1308         = fgGetNode("/position/longitude-deg");
1309     static const SGPropertyNode *latitude
1310         = fgGetNode("/position/latitude-deg");
1311     static const SGPropertyNode *cur_time_override
1312         = fgGetNode("/sim/time/cur-time-override", true);
1313
1314     SGPath zone( globals->get_fg_root() );
1315     zone.append( "Timezone" );
1316     SGTime *t = new SGTime( longitude->getDoubleValue()
1317                               * SGD_DEGREES_TO_RADIANS,
1318                             latitude->getDoubleValue()
1319                               * SGD_DEGREES_TO_RADIANS,
1320                             zone.str(),
1321                             cur_time_override->getLongValue() );
1322
1323     // Handle potential user specified time offsets
1324     time_t cur_time = t->get_cur_time();
1325     time_t currGMT = sgTimeGetGMT( gmtime(&cur_time) );
1326     time_t systemLocalTime = sgTimeGetGMT( localtime(&cur_time) );
1327     time_t aircraftLocalTime = 
1328         sgTimeGetGMT( fgLocaltime(&cur_time, t->get_zonename() ) );
1329
1330     // Okay, we now have six possible scenarios
1331     int offset = fgGetInt("/sim/startup/time-offset");
1332     const string &offset_type = fgGetString("/sim/startup/time-offset-type");
1333     if (offset_type == "system-offset") {
1334         globals->set_warp( offset );
1335     } else if (offset_type == "gmt-offset") {
1336         globals->set_warp( offset - (currGMT - systemLocalTime) );
1337     } else if (offset_type == "latitude-offset") {
1338         globals->set_warp( offset - (aircraftLocalTime - systemLocalTime) );
1339     } else if (offset_type == "system") {
1340         globals->set_warp( offset - cur_time );
1341     } else if (offset_type == "gmt") {
1342         globals->set_warp( offset - currGMT );
1343     } else if (offset_type == "latitude") {
1344         globals->set_warp( offset - (aircraftLocalTime - systemLocalTime) - 
1345                            cur_time ); 
1346     } else {
1347         SG_LOG( SG_GENERAL, SG_ALERT,
1348                 "FG_TIME::Unsupported offset type " << offset_type );
1349         exit( -1 );
1350     }
1351
1352     SG_LOG( SG_GENERAL, SG_INFO, "After time init, warp = " 
1353             << globals->get_warp() );
1354
1355     globals->set_warp_delta( 0 );
1356
1357     t->update( 0.0, 0.0,
1358                cur_time_override->getLongValue(),
1359                globals->get_warp() );
1360
1361     return t;
1362 }
1363
1364
1365 // This is the top level init routine which calls all the other
1366 // initialization routines.  If you are adding a subsystem to flight
1367 // gear, its initialization call should located in this routine.
1368 // Returns non-zero if a problem encountered.
1369 bool fgInitSubsystems() {
1370     static const SGPropertyNode *longitude
1371         = fgGetNode("/sim/presets/longitude-deg");
1372     static const SGPropertyNode *latitude
1373         = fgGetNode("/sim/presets/latitude-deg");
1374     static const SGPropertyNode *altitude
1375         = fgGetNode("/sim/presets/altitude-ft");
1376
1377     fgLIGHT *l = &cur_light_params;
1378
1379     SG_LOG( SG_GENERAL, SG_INFO, "Initialize Subsystems");
1380     SG_LOG( SG_GENERAL, SG_INFO, "========== ==========");
1381
1382
1383     ////////////////////////////////////////////////////////////////////
1384     // Initialize the material property subsystem.
1385     ////////////////////////////////////////////////////////////////////
1386
1387     SGPath mpath( globals->get_fg_root() );
1388     mpath.append( "materials.xml" );
1389     if ( ! material_lib.load( mpath.str() ) ) {
1390         SG_LOG( SG_GENERAL, SG_ALERT, "Error loading material lib!" );
1391         exit(-1);
1392     }
1393
1394     ////////////////////////////////////////////////////////////////////
1395     // Initialize the event manager subsystem.
1396     ////////////////////////////////////////////////////////////////////
1397
1398     global_events.init();
1399
1400     // Output event stats every 60 seconds
1401     global_events.Register( "FGEventMgr::print_stats()",
1402                             &global_events, &FGEventMgr::print_stats,
1403                             60000 );
1404
1405
1406     ////////////////////////////////////////////////////////////////////
1407     // Initialize the scenery management subsystem.
1408     ////////////////////////////////////////////////////////////////////
1409
1410     if ( globals->get_tile_mgr()->init() ) {
1411         // Load the local scenery data
1412         double visibility_meters = fgGetDouble("/environment/visibility-m");
1413                 
1414         globals->get_tile_mgr()->update( visibility_meters );
1415     } else {
1416         SG_LOG( SG_GENERAL, SG_ALERT, "Error in Tile Manager initialization!" );
1417         exit(-1);
1418     }
1419
1420     // cause refresh of viewer scenery timestamps every 15 seconds...
1421     global_events.Register( "FGTileMgr::refresh_view_timestamps()",
1422                             globals->get_tile_mgr(),
1423                             &FGTileMgr::refresh_view_timestamps,
1424                             15000 );
1425
1426     SG_LOG( SG_GENERAL, SG_DEBUG,
1427             "Current terrain elevation after tile mgr init " <<
1428             globals->get_scenery()->get_cur_elev() );
1429
1430
1431     ////////////////////////////////////////////////////////////////////
1432     // Initialize the flight model subsystem.
1433     ////////////////////////////////////////////////////////////////////
1434
1435     fgInitFDM();
1436         
1437     // allocates structures so must happen before any of the flight
1438     // model or control parameters are set
1439     fgAircraftInit();   // In the future this might not be the case.
1440
1441
1442     ////////////////////////////////////////////////////////////////////
1443     // Initialize the view manager subsystem.
1444     ////////////////////////////////////////////////////////////////////
1445
1446     fgInitView();
1447
1448
1449     ////////////////////////////////////////////////////////////////////
1450     // Initialize the lighting subsystem.
1451     ////////////////////////////////////////////////////////////////////
1452
1453     // fgUpdateSunPos() needs a few position and view parameters set
1454     // so it can calculate local relative sun angle and a few other
1455     // things for correctly orienting the sky.
1456     fgUpdateSunPos();
1457     fgUpdateMoonPos();
1458     global_events.Register( "fgUpdateSunPos()", &fgUpdateSunPos,
1459                             60000);
1460     global_events.Register( "fgUpdateMoonPos()", &fgUpdateMoonPos,
1461                             60000);
1462
1463     // Initialize Lighting interpolation tables
1464     l->Init();
1465
1466     // force one lighting update to make it right to start with...
1467     l->Update();
1468     // update the lighting parameters (based on sun angle)
1469     global_events.Register( "fgLight::Update()",
1470                             &cur_light_params, &fgLIGHT::Update,
1471                             30000 );
1472
1473
1474     ////////////////////////////////////////////////////////////////////
1475     // Create and register the logger.
1476     ////////////////////////////////////////////////////////////////////
1477     
1478     globals->get_subsystem_mgr()->add(FGSubsystemMgr::GENERAL,
1479                                       "logger",
1480                                       new FGLogger);
1481
1482
1483     ////////////////////////////////////////////////////////////////////
1484     // Create and register the script manager.
1485     ////////////////////////////////////////////////////////////////////
1486
1487     globals->get_subsystem_mgr()->add(FGSubsystemMgr::GENERAL,
1488                                       "scripting",
1489                                       new FGScriptMgr);
1490
1491
1492     ////////////////////////////////////////////////////////////////////
1493     // Create and register the XML GUI.
1494     ////////////////////////////////////////////////////////////////////
1495
1496     globals->get_subsystem_mgr()->add(FGSubsystemMgr::INIT,
1497                                       "gui",
1498                                       new NewGUI);
1499
1500
1501     ////////////////////////////////////////////////////////////////////
1502     // Initialize the local time subsystem.
1503     ////////////////////////////////////////////////////////////////////
1504
1505     // update the current timezone each 30 minutes
1506     global_events.Register( "fgUpdateLocalTime()", &fgUpdateLocalTime,
1507                             30*60*1000 );
1508
1509
1510     ////////////////////////////////////////////////////////////////////
1511     // Initialize the weather subsystem.
1512     ////////////////////////////////////////////////////////////////////
1513
1514     // Initialize the weather modeling subsystem
1515 #ifdef FG_WEATHERCM
1516     // Initialize the WeatherDatabase
1517     SG_LOG(SG_GENERAL, SG_INFO, "Creating LocalWeatherDatabase");
1518     sgVec3 position;
1519     sgSetVec3( position, current_aircraft.fdm_state->get_Latitude(),
1520                current_aircraft.fdm_state->get_Longitude(),
1521                current_aircraft.fdm_state->get_Altitude() * SG_FEET_TO_METER );
1522     double init_vis = fgGetDouble("/environment/visibility-m");
1523
1524     FGLocalWeatherDatabase::DatabaseWorkingType working_type;
1525
1526     if (!strcmp(fgGetString("/environment/weather/working-type"), "internet"))
1527     {
1528       working_type = FGLocalWeatherDatabase::use_internet;
1529     } else {
1530       working_type = FGLocalWeatherDatabase::default_mode;
1531     }
1532     
1533     if ( init_vis > 0 ) {
1534       FGLocalWeatherDatabase::theFGLocalWeatherDatabase = 
1535         new FGLocalWeatherDatabase( position,
1536                                     globals->get_fg_root(),
1537                                     working_type,
1538                                     init_vis );
1539     } else {
1540       FGLocalWeatherDatabase::theFGLocalWeatherDatabase = 
1541         new FGLocalWeatherDatabase( position,
1542                                     globals->get_fg_root(),
1543                                     working_type );
1544     }
1545
1546     // cout << theFGLocalWeatherDatabase << endl;
1547     // cout << "visibility = " 
1548     //      << theFGLocalWeatherDatabase->getWeatherVisibility() << endl;
1549
1550     WeatherDatabase = FGLocalWeatherDatabase::theFGLocalWeatherDatabase;
1551
1552     // register the periodic update of the weather
1553     global_events.Register( "weather update", &fgUpdateWeatherDatabase,
1554                             30000);
1555 #else
1556     globals->get_environment_mgr()->init();
1557     globals->get_environment_mgr()->bind();
1558 #endif
1559
1560 #ifdef FG_USE_CLOUDS_3D
1561     ////////////////////////////////////////////////////////////////////
1562     // Initialize the 3D cloud subsystem.
1563     ////////////////////////////////////////////////////////////////////
1564     if ( fgGetBool("/sim/rendering/clouds3d") ) {
1565         SGPath cloud_path(globals->get_fg_root());
1566         cloud_path.append("large.sky");
1567         SG_LOG(SG_GENERAL, SG_INFO, "Loading CLOUDS3d from: " << cloud_path.c_str());
1568         if ( !sgCloud3d->Load( cloud_path.str(),
1569                                latitude->getDoubleValue(),
1570                                longitude->getDoubleValue()) )
1571         {
1572             fgSetBool("/sim/rendering/clouds3d", false);
1573             SG_LOG(SG_GENERAL, SG_INFO, "CLOUDS3d FAILED: ");
1574         }
1575         SG_LOG(SG_GENERAL, SG_INFO, "CLOUDS3d Loaded: ");
1576     }
1577 #endif
1578
1579     ////////////////////////////////////////////////////////////////////
1580     // Initialize vor/ndb/ils/fix list management and query systems
1581     ////////////////////////////////////////////////////////////////////
1582
1583     SG_LOG(SG_GENERAL, SG_INFO, "Loading Navaids");
1584
1585     SG_LOG(SG_GENERAL, SG_INFO, "  VOR/NDB");
1586     current_navlist = new FGNavList;
1587     SGPath p_nav( globals->get_fg_root() );
1588     p_nav.append( "Navaids/default.nav" );
1589     current_navlist->init( p_nav );
1590
1591     SG_LOG(SG_GENERAL, SG_INFO, "  ILS and Marker Beacons");
1592     current_beacons = new FGMarkerBeacons;
1593     current_beacons->init();
1594     current_ilslist = new FGILSList;
1595     SGPath p_ils( globals->get_fg_root() );
1596     p_ils.append( "Navaids/default.ils" );
1597     current_ilslist->init( p_ils );
1598
1599     SG_LOG(SG_GENERAL, SG_INFO, "  Fixes");
1600     current_fixlist = new FGFixList;
1601     SGPath p_fix( globals->get_fg_root() );
1602     p_fix.append( "Navaids/default.fix" );
1603     current_fixlist->init( p_fix );
1604
1605     ////////////////////////////////////////////////////////////////////
1606     // Initialize ATC list management and query systems
1607     ////////////////////////////////////////////////////////////////////
1608
1609     SG_LOG(SG_GENERAL, SG_INFO, "  ATIS");
1610     current_atislist = new FGATISList;
1611     SGPath p_atis( globals->get_fg_root() );
1612     p_atis.append( "ATC/default.atis" );
1613     current_atislist->init( p_atis );
1614
1615     SG_LOG(SG_GENERAL, SG_INFO, "  Tower");
1616     current_towerlist = new FGTowerList;
1617     SGPath p_tower( globals->get_fg_root() );
1618     p_tower.append( "ATC/default.tower" );
1619     current_towerlist->init( p_tower );
1620
1621     SG_LOG(SG_GENERAL, SG_INFO, "  Approach");
1622     current_approachlist = new FGApproachList;
1623     SGPath p_approach( globals->get_fg_root() );
1624     p_approach.append( "ATC/default.approach" );
1625     current_approachlist->init( p_approach );
1626
1627     ////////////////////////////////////////////////////////////////////
1628     // Initialise ATC display system
1629     ////////////////////////////////////////////////////////////////////
1630
1631     SG_LOG(SG_GENERAL, SG_INFO, "  ATC Display");
1632     globals->set_ATC_display(new FGATCDisplay);
1633     globals->get_ATC_display()->init(); 
1634
1635     ////////////////////////////////////////////////////////////////////
1636     // Initialise the ATC Manager 
1637     ////////////////////////////////////////////////////////////////////
1638
1639     SG_LOG(SG_GENERAL, SG_INFO, "  ATC Manager");
1640     globals->set_ATC_mgr(new FGATCMgr);
1641     globals->get_ATC_mgr()->init(); 
1642     
1643     ////////////////////////////////////////////////////////////////////
1644     // Initialise the AI Manager 
1645     ////////////////////////////////////////////////////////////////////
1646
1647     if (fgGetBool("/sim/ai-traffic/enabled")) {
1648         SG_LOG(SG_GENERAL, SG_INFO, "  AI Manager");
1649         globals->set_AI_mgr(new FGAIMgr);
1650         globals->get_AI_mgr()->init();
1651     }
1652
1653 #ifdef ENABLE_AUDIO_SUPPORT
1654     ////////////////////////////////////////////////////////////////////
1655     // Initialize the sound subsystem.
1656     ////////////////////////////////////////////////////////////////////
1657
1658     globals->set_soundmgr(new FGSoundMgr);
1659     globals->get_soundmgr()->init();
1660     globals->get_soundmgr()->bind();
1661
1662
1663     ////////////////////////////////////////////////////////////////////
1664     // Initialize the sound-effects subsystem.
1665     ////////////////////////////////////////////////////////////////////
1666
1667     globals->get_subsystem_mgr()->add(FGSubsystemMgr::GENERAL,
1668                                       "fx",
1669                                       new FGFX);
1670     
1671
1672 #endif
1673
1674     globals->get_subsystem_mgr()->add(FGSubsystemMgr::GENERAL,
1675                                       "instrumentation",
1676                                       new FGInstrumentMgr);
1677     globals->get_subsystem_mgr()->add(FGSubsystemMgr::GENERAL,
1678                                       "systems",
1679                                       new FGSystemMgr);
1680
1681     ////////////////////////////////////////////////////////////////////
1682     // Initialize the radio stack subsystem.
1683     ////////////////////////////////////////////////////////////////////
1684
1685                                 // A textbook example of how FGSubsystem
1686                                 // should work...
1687     current_radiostack = new FGRadioStack;
1688     current_radiostack->init();
1689     current_radiostack->bind();
1690
1691
1692     ////////////////////////////////////////////////////////////////////
1693     // Initialize the cockpit subsystem
1694     ////////////////////////////////////////////////////////////////////
1695
1696     if( fgCockpitInit( &current_aircraft )) {
1697         // Cockpit initialized ok.
1698     } else {
1699         SG_LOG( SG_GENERAL, SG_ALERT, "Error in Cockpit initialization!" );
1700         exit(-1);
1701     }
1702
1703
1704     ////////////////////////////////////////////////////////////////////
1705     // Initialize the autopilot subsystem.
1706     ////////////////////////////////////////////////////////////////////
1707
1708     globals->set_autopilot(new FGAutopilot);
1709     globals->get_autopilot()->init();
1710     globals->get_autopilot()->bind();
1711
1712                                 // FIXME: these should go in the
1713                                 // GUI initialization code, not here.
1714     fgAPAdjustInit();
1715     NewTgtAirportInit();
1716     NewHeadingInit();
1717     NewAltitudeInit();
1718
1719     ////////////////////////////////////////////////////////////////////
1720     // Initialize I/O subsystem.
1721     ////////////////////////////////////////////////////////////////////
1722
1723     globals->get_io()->init();
1724     globals->get_io()->bind();
1725
1726     // Initialize the 2D panel.
1727     string panel_path = fgGetString("/sim/panel/path",
1728                                     "Panels/Default/default.xml");
1729     current_panel = fgReadPanel(panel_path);
1730     if (current_panel == 0) {
1731         SG_LOG( SG_INPUT, SG_ALERT, 
1732                 "Error reading new panel from " << panel_path );
1733     } else {
1734         SG_LOG( SG_INPUT, SG_INFO, "Loaded new panel from " << panel_path );
1735         current_panel->init();
1736         current_panel->bind();
1737     }
1738
1739     
1740     ////////////////////////////////////////////////////////////////////
1741     // Initialize the default (kludged) properties.
1742     ////////////////////////////////////////////////////////////////////
1743
1744     fgInitProps();
1745
1746
1747     ////////////////////////////////////////////////////////////////////
1748     // Initialize the controls subsystem.
1749     ////////////////////////////////////////////////////////////////////
1750
1751     globals->get_controls()->init();
1752     globals->get_controls()->bind();
1753
1754
1755     ////////////////////////////////////////////////////////////////////
1756     // Initialize the steam subsystem.
1757     ////////////////////////////////////////////////////////////////////
1758
1759     globals->get_steam()->init();
1760     globals->get_steam()->bind();
1761
1762
1763     ////////////////////////////////////////////////////////////////////
1764     // Initialize the input subsystem.
1765     ////////////////////////////////////////////////////////////////////
1766
1767     globals->get_subsystem_mgr()->add(FGSubsystemMgr::GENERAL,
1768                                       "input",
1769                                       new FGInput);
1770
1771
1772     ////////////////////////////////////////////////////////////////////
1773     // Bind and initialize subsystems.
1774     ////////////////////////////////////////////////////////////////////
1775
1776     globals->get_subsystem_mgr()->bind();
1777     globals->get_subsystem_mgr()->init();
1778
1779
1780     ////////////////////////////////////////////////////////////////////////
1781     // End of subsystem initialization.
1782     ////////////////////////////////////////////////////////////////////
1783
1784     SG_LOG( SG_GENERAL, SG_INFO, endl);
1785
1786                                 // Save the initial state for future
1787                                 // reference.
1788     globals->saveInitialState();
1789
1790     return true;
1791 }
1792
1793
1794 void fgReInitSubsystems()
1795 {
1796     static const SGPropertyNode *longitude
1797         = fgGetNode("/sim/presets/longitude-deg");
1798     static const SGPropertyNode *latitude
1799         = fgGetNode("/sim/presets/latitude-deg");
1800     static const SGPropertyNode *altitude
1801         = fgGetNode("/sim/presets/altitude-ft");
1802     static const SGPropertyNode *master_freeze
1803         = fgGetNode("/sim/freeze/master");
1804
1805     SG_LOG( SG_GENERAL, SG_INFO,
1806             "fgReInitSubsystems(): /position/altitude = "
1807             << altitude->getDoubleValue() );
1808
1809     bool freeze = master_freeze->getBoolValue();
1810     if ( !freeze ) {
1811         fgSetBool("/sim/freeze/master", true);
1812     }
1813
1814     // Initialize the FDM
1815     fgInitFDM();
1816     
1817     // allocates structures so must happen before any of the flight
1818     // model or control parameters are set
1819     fgAircraftInit();   // In the future this might not be the case.
1820
1821     // copy viewer settings into current-view path
1822     globals->get_viewmgr()->copyToCurrent();
1823
1824     fgInitView();
1825
1826     globals->get_controls()->reset_all();
1827     globals->get_autopilot()->reset();
1828
1829     fgUpdateSunPos();
1830     fgUpdateMoonPos();
1831     cur_light_params.Update();
1832     fgUpdateLocalTime();
1833
1834     if ( !freeze ) {
1835         fgSetBool("/sim/freeze/master", false);
1836     }
1837 }
1838