// fg_init.cxx -- Flight Gear top level initialization routines // // Written by Curtis Olson, started August 1997. // // Copyright (C) 1997 Curtis L. Olson - curt@infoplane.com // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License as // published by the Free Software Foundation; either version 2 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, but // WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. // // // $Id$ #ifdef HAVE_CONFIG_H # include <config.h> #endif // For BC 5.01 this must be included before OpenGL includes. #ifdef SG_MATH_EXCEPTION_CLASH # include <math.h> #endif #include <stdio.h> #include <stdlib.h> #include <string.h> // strcmp() #if defined( unix ) || defined( __CYGWIN__ ) # include <unistd.h> // for gethostname() #endif // work around a stdc++ lib bug in some versions of linux, but doesn't // seem to hurt to have this here for all versions of Linux. #ifdef linux # define _G_NO_EXTERN_TEMPLATES #endif #include <simgear/compiler.h> #include STL_STRING #include <simgear/constants.h> #include <simgear/debug/logstream.hxx> #include <simgear/structure/exception.hxx> #include <simgear/structure/event_mgr.hxx> #include <simgear/math/point3d.hxx> #include <simgear/math/polar3d.hxx> #include <simgear/math/sg_geodesy.hxx> #include <simgear/misc/sg_path.hxx> #include <simgear/scene/material/matlib.hxx> #ifdef FG_USE_CLOUDS_3D # include <simgear/scene/sky/clouds3d/SkySceneLoader.hpp> # include <simgear/scene/sky/clouds3d/SkyUtil.hpp> # include <simgear/screen/texture.hxx> #endif #include <simgear/timing/sg_time.hxx> #include <simgear/timing/lowleveltime.h> #include <Aircraft/aircraft.hxx> #include <FDM/UIUCModel/uiuc_aircraftdir.h> #include <Airports/runways.hxx> #include <Airports/simple.hxx> #include <ATC/ATCdisplay.hxx> #include <ATC/ATCmgr.hxx> #include <ATC/AIMgr.hxx> #include <Autopilot/auto_gui.hxx> #include <Autopilot/newauto.hxx> #include <Cockpit/cockpit.hxx> #include <Cockpit/radiostack.hxx> #include <Cockpit/panel.hxx> #include <Cockpit/panel_io.hxx> #include <FDM/ADA.hxx> #include <FDM/Balloon.h> #include <FDM/ExternalNet/ExternalNet.hxx> #include <FDM/ExternalPipe/ExternalPipe.hxx> #include <FDM/JSBSim/JSBSim.hxx> #include <FDM/LaRCsim/LaRCsim.hxx> #include <FDM/MagicCarpet.hxx> #include <FDM/UFO.hxx> #include <FDM/NullFDM.hxx> #include <FDM/YASim/YASim.hxx> #include <GUI/new_gui.hxx> #include <Include/general.hxx> #include <Input/input.hxx> #include <Instrumentation/instrument_mgr.hxx> #include <Model/acmodel.hxx> #include <AIModel/AIManager.hxx> #include <Navaids/fixlist.hxx> #include <Navaids/ilslist.hxx> #include <Navaids/mkrbeacons.hxx> #include <Navaids/navlist.hxx> #include <Replay/replay.hxx> #include <Scenery/scenery.hxx> #include <Scenery/tilemgr.hxx> #if defined(HAVE_PLIB_PSL) #include <Scripting/scriptmgr.hxx> #endif #include <Scripting/NasalSys.hxx> #include <Sound/fg_fx.hxx> #include <Systems/system_mgr.hxx> #include <Time/light.hxx> #include <Time/moonpos.hxx> #include <Time/sunpos.hxx> #include <Time/sunsolver.hxx> #include <Time/tmp.hxx> #ifdef FG_MPLAYER_AS #include <MultiPlayer/multiplaytxmgr.hxx> #include <MultiPlayer/multiplayrxmgr.hxx> #endif #ifdef FG_WEATHERCM # include <WeatherCM/FGLocalWeatherDatabase.h> #else # include <Environment/environment_mgr.hxx> #endif #include "fg_init.hxx" #include "fg_io.hxx" #include "fg_commands.hxx" #include "fg_props.hxx" #include "options.hxx" #include "globals.hxx" #include "logger.hxx" #include "viewmgr.hxx" #if defined(FX) && defined(XMESA) #include <GL/xmesa.h> #endif SG_USING_STD(string); class Sound; extern const char *default_root; #ifdef FG_USE_CLOUDS_3D SkySceneLoader *sgCloud3d; #endif // Scan the command line options for the specified option and return // the value. static string fgScanForOption( const string& option, int argc, char **argv ) { int i = 1; SG_LOG(SG_GENERAL, SG_INFO, "Scanning command line for: " << option ); int len = option.length(); while ( i < argc ) { SG_LOG( SG_GENERAL, SG_DEBUG, "argv[" << i << "] = " << argv[i] ); string arg = argv[i]; if ( arg.find( option ) == 0 ) { return arg.substr( len ); } i++; } return ""; } // Scan the user config files for the specified option and return // the value. static string fgScanForOption( const string& option, const string& path ) { sg_gzifstream in( path ); if ( !in.is_open() ) { return ""; } SG_LOG( SG_GENERAL, SG_INFO, "Scanning " << path << " for: " << option ); int len = option.length(); in >> skipcomment; #ifndef __MWERKS__ while ( ! in.eof() ) { #else char c = '\0'; while ( in.get(c) && c != '\0' ) { in.putback(c); #endif string line; #if defined( macintosh ) getline( in, line, '\r' ); #else getline( in, line, '\n' ); #endif // catch extraneous (DOS) line ending character if ( line[line.length() - 1] < 32 ) { line = line.substr( 0, line.length()-1 ); } if ( line.find( option ) == 0 ) { return line.substr( len ); } in >> skipcomment; } return ""; } // Read in configuration (files and command line options) but only set // fg_root bool fgInitFGRoot ( int argc, char **argv ) { string root; char* envp; // First parse command line options looking for --fg-root=, this // will override anything specified in a config file root = fgScanForOption( "--fg-root=", argc, argv); #if defined( unix ) || defined( __CYGWIN__ ) // Next check home directory for .fgfsrc.hostname file if ( root.empty() ) { envp = ::getenv( "HOME" ); if ( envp != NULL ) { SGPath config( envp ); config.append( ".fgfsrc" ); char name[256]; gethostname( name, 256 ); config.concat( "." ); config.concat( name ); root = fgScanForOption( "--fg-root=", config.str() ); } } #endif // Next check home directory for .fgfsrc file if ( root.empty() ) { envp = ::getenv( "HOME" ); if ( envp != NULL ) { SGPath config( envp ); config.append( ".fgfsrc" ); root = fgScanForOption( "--fg-root=", config.str() ); } } // Next check if fg-root is set as an env variable if ( root.empty() ) { envp = ::getenv( "FG_ROOT" ); if ( envp != NULL ) { root = envp; } } // Otherwise, default to a random compiled-in location if we can't // find fg-root any other way. if ( root.empty() ) { #if defined( __CYGWIN__ ) root = "/FlightGear"; #elif defined( WIN32 ) root = "\\FlightGear"; #elif defined(OSX_BUNDLE) /* the following code looks for the base package directly inside the application bundle. This can be changed fairly easily by fiddling with the code below. And yes, I know it's ugly and verbose. */ CFBundleRef appBundle = CFBundleGetMainBundle(); CFURLRef appUrl = CFBundleCopyBundleURL(appBundle); CFRelease(appBundle); // look for a 'data' subdir directly inside the bundle : is there // a better place? maybe in Resources? I don't know ... CFURLRef dataDir = CFURLCreateCopyAppendingPathComponent(NULL, appUrl, CFSTR("data"), true); // now convert down to a path, and the a c-string CFStringRef path = CFURLCopyFileSystemPath(dataDir, kCFURLPOSIXPathStyle); root = CFStringGetCStringPtr(path, CFStringGetSystemEncoding()); // tidy up. CFRelease(appBundle); CFRelease(dataDir); CFRelease(path); #else root = PKGLIBDIR; #endif } SG_LOG(SG_INPUT, SG_INFO, "fg_root = " << root ); globals->set_fg_root(root); return true; } // Read in configuration (files and command line options) but only set // aircraft bool fgInitFGAircraft ( int argc, char **argv ) { string aircraft; char* envp; // First parse command line options looking for --aircraft=, this // will override anything specified in a config file aircraft = fgScanForOption( "--aircraft=", argc, argv ); #if defined( unix ) || defined( __CYGWIN__ ) // Next check home directory for .fgfsrc.hostname file if ( aircraft.empty() ) { envp = ::getenv( "HOME" ); if ( envp != NULL ) { SGPath config( envp ); config.append( ".fgfsrc" ); char name[256]; gethostname( name, 256 ); config.concat( "." ); config.concat( name ); aircraft = fgScanForOption( "--aircraft=", config.str() ); } } #endif // Next check home directory for .fgfsrc file if ( aircraft.empty() ) { envp = ::getenv( "HOME" ); if ( envp != NULL ) { SGPath config( envp ); config.append( ".fgfsrc" ); aircraft = fgScanForOption( "--aircraft=", config.str() ); } } // if an aircraft was specified, set the property name if ( !aircraft.empty() ) { SG_LOG(SG_INPUT, SG_INFO, "aircraft = " << aircraft ); fgSetString("/sim/aircraft", aircraft.c_str() ); } else { SG_LOG(SG_INPUT, SG_INFO, "No user specified aircraft, using default" ); } return true; } // Return the current base package version string fgBasePackageVersion() { SGPath base_path( globals->get_fg_root() ); base_path.append("version"); sg_gzifstream in( base_path.str() ); if ( !in.is_open() ) { SGPath old_path( globals->get_fg_root() ); old_path.append( "Thanks" ); sg_gzifstream old( old_path.str() ); if ( !old.is_open() ) { return "[none]"; } else { return "[old version]"; } } string version; in >> version; return version; } // Initialize the localization SGPropertyNode *fgInitLocale(const char *language) { SGPropertyNode *c_node = NULL, *d_node = NULL; SGPropertyNode *intl = fgGetNode("/sim/intl"); SG_LOG(SG_GENERAL, SG_INFO, "Selecting language: " << language ); // localization not defined if (!intl) return NULL; // // Select the proper language from the list // vector<SGPropertyNode_ptr> locale = intl->getChildren("locale"); for (unsigned int i = 0; i < locale.size(); i++) { vector<SGPropertyNode_ptr> lang = locale[i]->getChildren("lang"); for (unsigned int j = 0; j < lang.size(); j++) { if (!strcmp(lang[j]->getStringValue(), language)) { c_node = locale[i]; break; } } } // Get the defaults d_node = intl->getChild("locale"); if (!c_node) c_node = d_node; // Check for localized font SGPropertyNode *font_n = c_node->getNode("font", true); if ( !strcmp(font_n->getStringValue(), "") ) font_n->setStringValue(d_node->getStringValue("font", "typewriter.txf")); // // Load the default strings // SGPath d_path( globals->get_fg_root() ); const char *d_path_str = d_node->getStringValue("strings"); if (!d_path_str) { SG_LOG(SG_GENERAL, SG_ALERT, "Incorrect path in configuration file."); return NULL; } d_path.append(d_path_str); SG_LOG(SG_GENERAL, SG_INFO, "Reading localized strings from " << d_path.str()); SGPropertyNode *strings = c_node->getNode("strings"); try { readProperties(d_path.str(), strings); } catch (const sg_exception &e) { SG_LOG(SG_GENERAL, SG_ALERT, "Unable to read the localized strings"); return NULL; } // // Load the language specific strings // if (c_node != d_node) { SGPath c_path( globals->get_fg_root() ); const char *c_path_str = c_node->getStringValue("strings"); if (!c_path_str) { SG_LOG(SG_GENERAL, SG_ALERT, "Incorrect path in configuration file."); return NULL; } c_path.append(c_path_str); SG_LOG(SG_GENERAL, SG_INFO, "Reading localized strings from " << c_path.str()); try { readProperties(c_path.str(), strings); } catch (const sg_exception &e) { SG_LOG(SG_GENERAL, SG_ALERT, "Unable to read the localized strings"); return NULL; } } return c_node; } // Initialize the localization routines bool fgDetectLanguage() { char *language = ::getenv("LANG"); if (language == NULL) { SG_LOG(SG_GENERAL, SG_INFO, "Unable to detect the language" ); language = "C"; } SGPropertyNode *locale = fgInitLocale(language); if (!locale) { SG_LOG(SG_GENERAL, SG_ALERT, "No internationalization settings specified in preferences.xml" ); return false; } globals->set_locale( locale ); return true; } // Attempt to locate and parse the various non-XML config files in order // from least precidence to greatest precidence static void do_options (int argc, char ** argv) { // Check for $fg_root/system.fgfsrc SGPath config( globals->get_fg_root() ); config.append( "system.fgfsrc" ); fgParseOptions(config.str()); #if defined( unix ) || defined( __CYGWIN__ ) char name[256]; // Check for $fg_root/system.fgfsrc.hostname gethostname( name, 256 ); config.concat( "." ); config.concat( name ); fgParseOptions(config.str()); #endif // Check for ~/.fgfsrc char* envp = ::getenv( "HOME" ); if ( envp != NULL ) { config.set( envp ); config.append( ".fgfsrc" ); fgParseOptions(config.str()); } #if defined( unix ) || defined( __CYGWIN__ ) // Check for ~/.fgfsrc.hostname gethostname( name, 256 ); config.concat( "." ); config.concat( name ); fgParseOptions(config.str()); #endif // Parse remaining command line options // These will override anything specified in a config file fgParseArgs(argc, argv); } static string fgFindAircraftPath( const SGPath &path, const string &aircraft ) { ulDirEnt* dire; ulDir *dirp = ulOpenDir(path.str().c_str()); if (dirp == NULL) { cerr << "Unable to open aircraft directory." << endl; exit(-1); } while ((dire = ulReadDir(dirp)) != NULL) { if (dire->d_isdir) { if ( strcmp("CVS", dire->d_name) && strcmp(".", dire->d_name) && strcmp("..", dire->d_name) ) { SGPath next = path; next.append(dire->d_name); string result = fgFindAircraftPath( next, aircraft ); if ( ! result.empty() ) { return result; } } } else if ( !strcmp(dire->d_name, aircraft.c_str()) ) { return path.str(); } } ulCloseDir(dirp); return ""; } // Read in configuration (file and command line) bool fgInitConfig ( int argc, char **argv ) { // First, set some sane default values fgSetDefaults(); // Read global preferences from $FG_ROOT/preferences.xml SG_LOG(SG_INPUT, SG_INFO, "Reading global preferences"); fgLoadProps("preferences.xml", globals->get_props()); SG_LOG(SG_INPUT, SG_INFO, "Finished Reading global preferences"); // Detect the required language as early as possible if ( !fgDetectLanguage() ) { return false; } // Scan user config files and command line for a specified aircraft. fgInitFGAircraft(argc, argv); string aircraft = fgGetString( "/sim/aircraft", "" ); if ( aircraft.size() > 0 ) { SGPath aircraft_search( globals->get_fg_root() ); aircraft_search.append( "Aircraft" ); string aircraft_set = aircraft + "-set.xml"; string result = fgFindAircraftPath( aircraft_search, aircraft_set ); if ( !result.empty() ) { fgSetString( "/sim/aircraft-dir", result.c_str() ); SGPath full_name( result ); full_name.append( aircraft_set ); SG_LOG(SG_INPUT, SG_INFO, "Reading default aircraft: " << aircraft << " from " << full_name.str()); try { readProperties( full_name.str(), globals->get_props() ); } catch ( const sg_exception &e ) { string message = "Error reading default aircraft: "; message += e.getFormattedMessage(); SG_LOG(SG_INPUT, SG_ALERT, message); exit(2); } } else { SG_LOG( SG_INPUT, SG_ALERT, "Cannot find specified aircraft: " << aircraft ); } } else { SG_LOG( SG_INPUT, SG_ALERT, "No default aircraft specified" ); } // parse options after loading aircraft to ensure any user // overrides of defaults are honored. do_options(argc, argv); return true; } // find basic airport location info from airport database bool fgFindAirportID( const string& id, FGAirport *a ) { FGAirport result; if ( id.length() ) { SG_LOG( SG_GENERAL, SG_INFO, "Searching for airport code = " << id ); result = globals->get_airports()->search( id ); if ( result.id.empty() ) { SG_LOG( SG_GENERAL, SG_ALERT, "Failed to find " << id << " in basic.dat.gz" ); return false; } } else { return false; } *a = result; SG_LOG( SG_GENERAL, SG_INFO, "Position for " << id << " is (" << a->longitude << ", " << a->latitude << ")" ); return true; } // get airport elevation static double fgGetAirportElev( const string& id ) { FGAirport a; // double lon, lat; SG_LOG( SG_GENERAL, SG_INFO, "Finding elevation for airport: " << id ); if ( fgFindAirportID( id, &a ) ) { return a.elevation; } else { return -9999.0; } } // Preset lon/lat given an airport id static bool fgSetPosFromAirportID( const string& id ) { FGAirport a; // double lon, lat; SG_LOG( SG_GENERAL, SG_INFO, "Attempting to set starting position from airport code " << id ); if ( fgFindAirportID( id, &a ) ) { // presets fgSetDouble("/sim/presets/longitude-deg", a.longitude ); fgSetDouble("/sim/presets/latitude-deg", a.latitude ); // other code depends on the actual postition being set so set // that as well fgSetDouble("/position/longitude-deg", a.longitude ); fgSetDouble("/position/latitude-deg", a.latitude ); SG_LOG( SG_GENERAL, SG_INFO, "Position for " << id << " is (" << a.longitude << ", " << a.latitude << ")" ); return true; } else { return false; } } // Set current tower position lon/lat given an airport id static bool fgSetTowerPosFromAirportID( const string& id, double hdg ) { FGAirport a; // tower height hard coded for now... float towerheight=50.0f; // make a little off the heading for 1 runway airports... float fudge_lon = fabs(sin(hdg)) * .003f; float fudge_lat = .003f - fudge_lon; if ( fgFindAirportID( id, &a ) ) { fgSetDouble("/sim/tower/longitude-deg", a.longitude + fudge_lon); fgSetDouble("/sim/tower/latitude-deg", a.latitude + fudge_lat); fgSetDouble("/sim/tower/altitude-ft", a.elevation + towerheight); return true; } else { return false; } } // Set current_options lon/lat given an airport id and heading (degrees) static bool fgSetPosFromAirportIDandHdg( const string& id, double tgt_hdg ) { FGRunway r; if ( id.length() ) { // set initial position from runway and heading SG_LOG( SG_GENERAL, SG_INFO, "Attempting to set starting position from airport code " << id << " heading " << tgt_hdg ); if ( ! globals->get_runways()->search( id, (int)tgt_hdg, &r ) ) { SG_LOG( SG_GENERAL, SG_ALERT, "Failed to find a good runway for " << id << '\n' ); return false; } } else { return false; } double lat2, lon2, az2; double heading = r.heading; double azimuth = heading + 180.0; while ( azimuth >= 360.0 ) { azimuth -= 360.0; } SG_LOG( SG_GENERAL, SG_INFO, "runway = " << r.lon << ", " << r.lat << " length = " << r.length * SG_FEET_TO_METER << " heading = " << azimuth ); geo_direct_wgs_84 ( 0, r.lat, r.lon, azimuth, r.length * SG_FEET_TO_METER * 0.5 - 5.0, &lat2, &lon2, &az2 ); if ( fabs( fgGetDouble("/sim/presets/offset-distance") ) > SG_EPSILON ) { double olat, olon; double odist = fgGetDouble("/sim/presets/offset-distance"); odist *= SG_NM_TO_METER; double oaz = azimuth; if ( fabs(fgGetDouble("/sim/presets/offset-azimuth")) > SG_EPSILON ) { oaz = fgGetDouble("/sim/presets/offset-azimuth") + 180; heading = tgt_hdg; } while ( oaz >= 360.0 ) { oaz -= 360.0; } geo_direct_wgs_84 ( 0, lat2, lon2, oaz, odist, &olat, &olon, &az2 ); lat2=olat; lon2=olon; } // presets fgSetDouble("/sim/presets/longitude-deg", lon2 ); fgSetDouble("/sim/presets/latitude-deg", lat2 ); fgSetDouble("/sim/presets/heading-deg", heading ); // other code depends on the actual values being set ... fgSetDouble("/position/longitude-deg", lon2 ); fgSetDouble("/position/latitude-deg", lat2 ); fgSetDouble("/orientation/heading-deg", heading ); SG_LOG( SG_GENERAL, SG_INFO, "Position for " << id << " is (" << lon2 << ", " << lat2 << ") new heading is " << heading ); return true; } // Set current_options lon/lat given an airport id and runway number static bool fgSetPosFromAirportIDandRwy( const string& id, const string& rwy ) { FGRunway r; if ( id.length() ) { // set initial position from airport and runway number SG_LOG( SG_GENERAL, SG_INFO, "Attempting to set starting position for " << id << ":" << rwy ); if ( ! globals->get_runways()->search( id, rwy, &r ) ) { SG_LOG( SG_GENERAL, SG_ALERT, "Failed to find runway " << rwy << " at airport " << id ); return false; } } else { return false; } double lat2, lon2, az2; double heading = r.heading; double azimuth = heading + 180.0; while ( azimuth >= 360.0 ) { azimuth -= 360.0; } SG_LOG( SG_GENERAL, SG_INFO, "runway = " << r.lon << ", " << r.lat << " length = " << r.length * SG_FEET_TO_METER << " heading = " << azimuth ); geo_direct_wgs_84 ( 0, r.lat, r.lon, azimuth, r.length * SG_FEET_TO_METER * 0.5 - 5.0, &lat2, &lon2, &az2 ); if ( fabs( fgGetDouble("/sim/presets/offset-distance") ) > SG_EPSILON ) { double olat, olon; double odist = fgGetDouble("/sim/presets/offset-distance"); odist *= SG_NM_TO_METER; double oaz = azimuth; if ( fabs(fgGetDouble("/sim/presets/offset-azimuth")) > SG_EPSILON ) { oaz = fgGetDouble("/sim/presets/offset-azimuth") + 180; heading = fgGetDouble("/sim/presets/heading-deg"); } while ( oaz >= 360.0 ) { oaz -= 360.0; } geo_direct_wgs_84 ( 0, lat2, lon2, oaz, odist, &olat, &olon, &az2 ); lat2=olat; lon2=olon; } // presets fgSetDouble("/sim/presets/longitude-deg", lon2 ); fgSetDouble("/sim/presets/latitude-deg", lat2 ); fgSetDouble("/sim/presets/heading-deg", heading ); // other code depends on the actual values being set ... fgSetDouble("/position/longitude-deg", lon2 ); fgSetDouble("/position/latitude-deg", lat2 ); fgSetDouble("/orientation/heading-deg", heading ); SG_LOG( SG_GENERAL, SG_INFO, "Position for " << id << " is (" << lon2 << ", " << lat2 << ") new heading is " << heading ); return true; } static void fgSetDistOrAltFromGlideSlope() { // cout << "fgSetDistOrAltFromGlideSlope()" << endl; string apt_id = fgGetString("/sim/presets/airport-id"); double gs = fgGetDouble("/sim/presets/glideslope-deg") * SG_DEGREES_TO_RADIANS ; double od = fgGetDouble("/sim/presets/offset-distance"); double alt = fgGetDouble("/sim/presets/altitude-ft"); double apt_elev = 0.0; if ( ! apt_id.empty() ) { apt_elev = fgGetAirportElev( apt_id ); if ( apt_elev < -9990.0 ) { apt_elev = 0.0; } } else { apt_elev = 0.0; } if( fabs(gs) > 0.01 && fabs(od) > 0.1 && alt < -9990 ) { // set altitude from glideslope and offset-distance od *= SG_NM_TO_METER * SG_METER_TO_FEET; alt = fabs(od*tan(gs)) + apt_elev; fgSetDouble("/sim/presets/altitude-ft", alt); fgSetBool("/sim/presets/onground", false); SG_LOG( SG_GENERAL, SG_INFO, "Calculated altitude as: " << alt << " ft" ); } else if( fabs(gs) > 0.01 && alt > 0 && fabs(od) < 0.1) { // set offset-distance from glideslope and altitude od = (alt - apt_elev) / tan(gs); od *= -1*SG_FEET_TO_METER * SG_METER_TO_NM; fgSetDouble("/sim/presets/offset-distance", od); fgSetBool("/sim/presets/onground", false); SG_LOG( SG_GENERAL, SG_INFO, "Calculated offset distance as: " << od << " nm" ); } else if( fabs(gs) > 0.01 ) { SG_LOG( SG_GENERAL, SG_ALERT, "Glideslope given but not altitude or offset-distance." ); SG_LOG( SG_GENERAL, SG_ALERT, "Resetting glideslope to zero" ); fgSetDouble("/sim/presets/glideslope-deg", 0); fgSetBool("/sim/presets/onground", true); } } // Set current_options lon/lat given an airport id and heading (degrees) static bool fgSetPosFromNAV( const string& id, const double& freq ) { FGNav *nav = current_navlist->findByIdentAndFreq( id.c_str(), freq ); // set initial position from runway and heading if ( nav != NULL ) { SG_LOG( SG_GENERAL, SG_INFO, "Attempting to set starting position for " << id << ":" << freq ); double lon = nav->get_lon(); double lat = nav->get_lat(); if ( fabs( fgGetDouble("/sim/presets/offset-distance") ) > SG_EPSILON ) { double odist = fgGetDouble("/sim/presets/offset-distance") * SG_NM_TO_METER; double oaz = fabs(fgGetDouble("/sim/presets/offset-azimuth")) + 180.0; while ( oaz >= 360.0 ) { oaz -= 360.0; } double olat, olon, az2; geo_direct_wgs_84 ( 0, lat, lon, oaz, odist, &olat, &olon, &az2 ); lat = olat; lon = olon; } // presets fgSetDouble("/sim/presets/longitude-deg", lon ); fgSetDouble("/sim/presets/latitude-deg", lat ); // other code depends on the actual values being set ... fgSetDouble("/position/longitude-deg", lon ); fgSetDouble("/position/latitude-deg", lat ); fgSetDouble("/orientation/heading-deg", fgGetDouble("/sim/presets/heading-deg") ); SG_LOG( SG_GENERAL, SG_INFO, "Position for " << id << ":" << freq << " is (" << lon << ", "<< lat << ")" ); return true; } else { SG_LOG( SG_GENERAL, SG_ALERT, "Failed to locate NAV = " << id << ":" << freq ); return false; } } // Set current_options lon/lat given an airport id and heading (degrees) static bool fgSetPosFromFix( const string& id ) { FGFix fix; // set initial position from runway and heading if ( current_fixlist->query( id.c_str(), &fix ) ) { SG_LOG( SG_GENERAL, SG_INFO, "Attempting to set starting position for " << id ); double lon = fix.get_lon(); double lat = fix.get_lat(); if ( fabs( fgGetDouble("/sim/presets/offset-distance") ) > SG_EPSILON ) { double odist = fgGetDouble("/sim/presets/offset-distance") * SG_NM_TO_METER; double oaz = fabs(fgGetDouble("/sim/presets/offset-azimuth")) + 180.0; while ( oaz >= 360.0 ) { oaz -= 360.0; } double olat, olon, az2; geo_direct_wgs_84 ( 0, lat, lon, oaz, odist, &olat, &olon, &az2 ); lat = olat; lon = olon; } // presets fgSetDouble("/sim/presets/longitude-deg", lon ); fgSetDouble("/sim/presets/latitude-deg", lat ); // other code depends on the actual values being set ... fgSetDouble("/position/longitude-deg", lon ); fgSetDouble("/position/latitude-deg", lat ); fgSetDouble("/orientation/heading-deg", fgGetDouble("/sim/presets/heading-deg") ); SG_LOG( SG_GENERAL, SG_INFO, "Position for " << id << " is (" << lon << ", "<< lat << ")" ); return true; } else { SG_LOG( SG_GENERAL, SG_ALERT, "Failed to locate NAV = " << id ); return false; } } /** * Initialize vor/ndb/ils/fix list management and query systems (as * well as simple airport db list) */ bool fgInitNav () { SG_LOG(SG_GENERAL, SG_INFO, "Loading Simple Airport List"); SGPath p_simple( globals->get_fg_root() ); p_simple.append( "Airports/basic.dat" ); FGAirportList *airports = new FGAirportList( p_simple.str() ); globals->set_airports( airports ); SG_LOG(SG_GENERAL, SG_INFO, "Loading Runway List"); SGPath p_runway( globals->get_fg_root() ); p_runway.append( "Airports/runways.dat" ); FGRunwayList *runways = new FGRunwayList( p_runway.str() ); globals->set_runways( runways ); SG_LOG(SG_GENERAL, SG_INFO, "Loading Navaids"); SG_LOG(SG_GENERAL, SG_INFO, " VOR/NDB"); current_navlist = new FGNavList; SGPath p_nav( globals->get_fg_root() ); p_nav.append( "Navaids/default.nav" ); current_navlist->init( p_nav ); SG_LOG(SG_GENERAL, SG_INFO, " ILS and Marker Beacons"); current_beacons = new FGMarkerBeacons; current_beacons->init(); current_ilslist = new FGILSList; SGPath p_ils( globals->get_fg_root() ); p_ils.append( "Navaids/default.ils" ); current_ilslist->init( p_ils ); SG_LOG(SG_GENERAL, SG_INFO, " Fixes"); current_fixlist = new FGFixList; SGPath p_fix( globals->get_fg_root() ); p_fix.append( "Navaids/default.fix" ); current_fixlist->init( p_fix ); return true; } // Set the initial position based on presets (or defaults) bool fgInitPosition() { // cout << "fgInitPosition()" << endl; double gs = fgGetDouble("/sim/presets/glideslope-deg") * SG_DEGREES_TO_RADIANS ; double od = fgGetDouble("/sim/presets/offset-distance"); double alt = fgGetDouble("/sim/presets/altitude-ft"); bool set_pos = false; // If glideslope is specified, then calculate offset-distance or // altitude relative to glide slope if either of those was not // specified. if ( fabs( gs ) > 0.01 ) { fgSetDistOrAltFromGlideSlope(); } // If we have an explicit, in-range lon/lat, don't change it, just use it. // If not, check for an airport-id and use that. // If not, default to the middle of the KSFO field. // The default values for lon/lat are deliberately out of range // so that the airport-id can take effect; valid lon/lat will // override airport-id, however. double lon_deg = fgGetDouble("/sim/presets/longitude-deg"); double lat_deg = fgGetDouble("/sim/presets/latitude-deg"); if ( lon_deg >= -180.0 && lon_deg <= 180.0 && lat_deg >= -90.0 && lat_deg <= 90.0 ) { set_pos = true; } string apt = fgGetString("/sim/presets/airport-id"); string rwy_no = fgGetString("/sim/presets/runway"); double hdg = fgGetDouble("/sim/presets/heading-deg"); string vor = fgGetString("/sim/presets/vor-id"); double vor_freq = fgGetDouble("/sim/presets/vor-freq"); string ndb = fgGetString("/sim/presets/ndb-id"); double ndb_freq = fgGetDouble("/sim/presets/ndb-freq"); string fix = fgGetString("/sim/presets/fix"); if ( !set_pos && !apt.empty() && !rwy_no.empty() ) { // An airport + runway is requested if ( fgSetPosFromAirportIDandRwy( apt, rwy_no ) ) { // set tower position (a little off the heading for single // runway airports) fgSetTowerPosFromAirportID( apt, hdg ); set_pos = true; } } if ( !set_pos && !apt.empty() ) { // An airport is requested (find runway closest to hdg) if ( fgSetPosFromAirportIDandHdg( apt, hdg ) ) { // set tower position (a little off the heading for single // runway airports) fgSetTowerPosFromAirportID( apt, hdg ); set_pos = true; } } if ( !set_pos && !vor.empty() ) { // a VOR is requested if ( fgSetPosFromNAV( vor, vor_freq ) ) { set_pos = true; } } if ( !set_pos && !ndb.empty() ) { // an NDB is requested if ( fgSetPosFromNAV( ndb, ndb_freq ) ) { set_pos = true; } } if ( !set_pos && !fix.empty() ) { // a Fix is requested if ( fgSetPosFromFix( fix ) ) { set_pos = true; } } if ( !set_pos ) { // No lon/lat specified, no airport specified, default to // middle of KSFO field. fgSetDouble("/sim/presets/longitude-deg", -122.374843); fgSetDouble("/sim/presets/latitude-deg", 37.619002); } fgSetDouble( "/position/longitude-deg", fgGetDouble("/sim/presets/longitude-deg") ); fgSetDouble( "/position/latitude-deg", fgGetDouble("/sim/presets/latitude-deg") ); fgSetDouble( "/orientation/heading-deg", fgGetDouble("/sim/presets/heading-deg") ); // determine if this should be an on-ground or in-air start if ( fabs(gs) > 0.01 || fabs(od) > 0.1 || alt > 0.1 ) { fgSetBool("/sim/presets/onground", false); } else { fgSetBool("/sim/presets/onground", true); } return true; } // General house keeping initializations bool fgInitGeneral() { string root; #if defined(FX) && defined(XMESA) char *mesa_win_state; #endif SG_LOG( SG_GENERAL, SG_INFO, "General Initialization" ); SG_LOG( SG_GENERAL, SG_INFO, "======= ==============" ); root = globals->get_fg_root(); if ( ! root.length() ) { // No root path set? Then bail ... SG_LOG( SG_GENERAL, SG_ALERT, "Cannot continue without a path to the base package " << "being defined." ); exit(-1); } SG_LOG( SG_GENERAL, SG_INFO, "FG_ROOT = " << '"' << root << '"' << endl ); #if defined(FX) && defined(XMESA) // initialize full screen flag globals->set_fullscreen(false); if ( strstr ( general.get_glRenderer(), "Glide" ) ) { // Test for the MESA_GLX_FX env variable if ( (mesa_win_state = getenv( "MESA_GLX_FX" )) != NULL) { // test if we are fullscreen mesa/glide if ( (mesa_win_state[0] == 'f') || (mesa_win_state[0] == 'F') ) { globals->set_fullscreen(true); } } } #endif return true; } // Initialize the flight model subsystem. This just creates the // object. The actual fdm initialization is delayed until we get a // proper scenery elevation hit. This is checked for in main.cxx void fgInitFDM() { if ( cur_fdm_state ) { delete cur_fdm_state; cur_fdm_state = 0; } double dt = 1.0 / fgGetInt("/sim/model-hz"); aircraft_dir = fgGetString("/sim/aircraft-dir"); const string &model = fgGetString("/sim/flight-model"); try { if ( model == "larcsim" ) { cur_fdm_state = new FGLaRCsim( dt ); } else if ( model == "jsb" ) { cur_fdm_state = new FGJSBsim( dt ); } else if ( model == "ada" ) { cur_fdm_state = new FGADA( dt ); } else if ( model == "balloon" ) { cur_fdm_state = new FGBalloonSim( dt ); } else if ( model == "magic" ) { cur_fdm_state = new FGMagicCarpet( dt ); } else if ( model == "ufo" ) { cur_fdm_state = new FGUFO( dt ); } else if ( model == "external" ) { // external is a synonym for "--fdm=null" and is // maintained here for backwards compatibility cur_fdm_state = new FGNullFDM( dt ); } else if ( model.find("network") == 0 ) { string host = "localhost"; int port1 = 5501; int port2 = 5502; int port3 = 5503; string net_options = model.substr(8); string::size_type begin, end; begin = 0; // host end = net_options.find( ",", begin ); if ( end != string::npos ) { host = net_options.substr(begin, end - begin); begin = end + 1; } // port1 end = net_options.find( ",", begin ); if ( end != string::npos ) { port1 = atoi( net_options.substr(begin, end - begin).c_str() ); begin = end + 1; } // port2 end = net_options.find( ",", begin ); if ( end != string::npos ) { port2 = atoi( net_options.substr(begin, end - begin).c_str() ); begin = end + 1; } // port3 end = net_options.find( ",", begin ); if ( end != string::npos ) { port3 = atoi( net_options.substr(begin, end - begin).c_str() ); begin = end + 1; } cur_fdm_state = new FGExternalNet( dt, host, port1, port2, port3 ); } else if ( model.find("pipe") == 0 ) { string pipe_path = model.substr(5); cur_fdm_state = new FGExternalPipe( dt, pipe_path ); } else if ( model == "null" ) { cur_fdm_state = new FGNullFDM( dt ); } else if ( model == "yasim" ) { cur_fdm_state = new YASim( dt ); } else { SG_LOG(SG_GENERAL, SG_ALERT, "Unrecognized flight model '" << model << "', cannot init flight dynamics model."); exit(-1); } } catch ( ... ) { SG_LOG(SG_GENERAL, SG_ALERT, "FlightGear aborting\n\n"); exit(-1); } } static void printMat(const sgVec4 *mat, char *name="") { int i; SG_LOG(SG_GENERAL, SG_BULK, name ); for(i=0; i<4; i++) { SG_LOG(SG_GENERAL, SG_BULK, " " << mat[i][0] << " " << mat[i][1] << " " << mat[i][2] << " " << mat[i][3] ); } } // Initialize view parameters void fgInitView() { // force update of model so that viewer can get some data... globals->get_aircraft_model()->update(0); // run update for current view so that data is current... globals->get_viewmgr()->update(0); printMat(globals->get_current_view()->get_VIEW(),"VIEW"); printMat(globals->get_current_view()->get_UP(),"UP"); // printMat(globals->get_current_view()->get_LOCAL(),"LOCAL"); } SGTime *fgInitTime() { // Initialize time static const SGPropertyNode *longitude = fgGetNode("/position/longitude-deg"); static const SGPropertyNode *latitude = fgGetNode("/position/latitude-deg"); static const SGPropertyNode *cur_time_override = fgGetNode("/sim/time/cur-time-override", true); SGPath zone( globals->get_fg_root() ); zone.append( "Timezone" ); SGTime *t = new SGTime( longitude->getDoubleValue() * SGD_DEGREES_TO_RADIANS, latitude->getDoubleValue() * SGD_DEGREES_TO_RADIANS, zone.str(), cur_time_override->getLongValue() ); globals->set_warp_delta( 0 ); t->update( 0.0, 0.0, cur_time_override->getLongValue(), globals->get_warp() ); return t; } // set up a time offset (aka warp) if one is specified void fgInitTimeOffset() { static const SGPropertyNode *longitude = fgGetNode("/position/longitude-deg"); static const SGPropertyNode *latitude = fgGetNode("/position/latitude-deg"); static const SGPropertyNode *cur_time_override = fgGetNode("/sim/time/cur-time-override", true); // Handle potential user specified time offsets int orig_warp = globals->get_warp(); SGTime *t = globals->get_time_params(); time_t cur_time = t->get_cur_time(); time_t currGMT = sgTimeGetGMT( gmtime(&cur_time) ); time_t systemLocalTime = sgTimeGetGMT( localtime(&cur_time) ); time_t aircraftLocalTime = sgTimeGetGMT( fgLocaltime(&cur_time, t->get_zonename() ) ); // Okay, we now have several possible scenarios int offset = fgGetInt("/sim/startup/time-offset"); const string &offset_type = fgGetString("/sim/startup/time-offset-type"); int warp = 0; if ( offset_type == "real" ) { warp = 0; } else if ( offset_type == "dawn" ) { warp = fgTimeSecondsUntilSunAngle( cur_time, longitude->getDoubleValue() * SGD_DEGREES_TO_RADIANS, latitude->getDoubleValue() * SGD_DEGREES_TO_RADIANS, 90.0, true ); } else if ( offset_type == "morning" ) { warp = fgTimeSecondsUntilSunAngle( cur_time, longitude->getDoubleValue() * SGD_DEGREES_TO_RADIANS, latitude->getDoubleValue() * SGD_DEGREES_TO_RADIANS, 75.0, true ); } else if ( offset_type == "noon" ) { warp = fgTimeSecondsUntilSunAngle( cur_time, longitude->getDoubleValue() * SGD_DEGREES_TO_RADIANS, latitude->getDoubleValue() * SGD_DEGREES_TO_RADIANS, 0.0, true ); } else if ( offset_type == "afternoon" ) { warp = fgTimeSecondsUntilSunAngle( cur_time, longitude->getDoubleValue() * SGD_DEGREES_TO_RADIANS, latitude->getDoubleValue() * SGD_DEGREES_TO_RADIANS, 60.0, false ); } else if ( offset_type == "dusk" ) { warp = fgTimeSecondsUntilSunAngle( cur_time, longitude->getDoubleValue() * SGD_DEGREES_TO_RADIANS, latitude->getDoubleValue() * SGD_DEGREES_TO_RADIANS, 90.0, false ); } else if ( offset_type == "evening" ) { warp = fgTimeSecondsUntilSunAngle( cur_time, longitude->getDoubleValue() * SGD_DEGREES_TO_RADIANS, latitude->getDoubleValue() * SGD_DEGREES_TO_RADIANS, 100.0, false ); } else if ( offset_type == "midnight" ) { warp = fgTimeSecondsUntilSunAngle( cur_time, longitude->getDoubleValue() * SGD_DEGREES_TO_RADIANS, latitude->getDoubleValue() * SGD_DEGREES_TO_RADIANS, 180.0, false ); } else if ( offset_type == "system-offset" ) { warp = offset; } else if ( offset_type == "gmt-offset" ) { warp = offset - (currGMT - systemLocalTime); } else if ( offset_type == "latitude-offset" ) { warp = offset - (aircraftLocalTime - systemLocalTime); } else if ( offset_type == "system" ) { warp = offset - cur_time; } else if ( offset_type == "gmt" ) { warp = offset - currGMT; } else if ( offset_type == "latitude" ) { warp = offset - (aircraftLocalTime - systemLocalTime) - cur_time; } else { SG_LOG( SG_GENERAL, SG_ALERT, "FG_TIME::Unsupported offset type " << offset_type ); exit( -1 ); } globals->set_warp( orig_warp + warp ); t->update( longitude->getDoubleValue() * SGD_DEGREES_TO_RADIANS, latitude->getDoubleValue() * SGD_DEGREES_TO_RADIANS, cur_time_override->getLongValue(), globals->get_warp() ); SG_LOG( SG_GENERAL, SG_INFO, "After fgInitTimeOffset(): warp = " << globals->get_warp() ); } // This is the top level init routine which calls all the other // initialization routines. If you are adding a subsystem to flight // gear, its initialization call should located in this routine. // Returns non-zero if a problem encountered. bool fgInitSubsystems() { // static const SGPropertyNode *longitude // = fgGetNode("/sim/presets/longitude-deg"); // static const SGPropertyNode *latitude // = fgGetNode("/sim/presets/latitude-deg"); // static const SGPropertyNode *altitude // = fgGetNode("/sim/presets/altitude-ft"); FGLight *l = (FGLight *)(globals->get_subsystem("lighting")); SG_LOG( SG_GENERAL, SG_INFO, "Initialize Subsystems"); SG_LOG( SG_GENERAL, SG_INFO, "========== =========="); //////////////////////////////////////////////////////////////////// // Initialize the event manager subsystem. //////////////////////////////////////////////////////////////////// globals->get_event_mgr()->init(); globals->get_event_mgr()->setFreezeProperty(fgGetNode("/sim/freeze/clock")); //////////////////////////////////////////////////////////////////// // Initialize the material property subsystem. //////////////////////////////////////////////////////////////////// SGPath mpath( globals->get_fg_root() ); mpath.append( "materials.xml" ); if ( ! globals->get_matlib()->load(globals->get_fg_root(), mpath.str()) ) { SG_LOG( SG_GENERAL, SG_ALERT, "Error loading material lib!" ); exit(-1); } //////////////////////////////////////////////////////////////////// // Initialize the scenery management subsystem. //////////////////////////////////////////////////////////////////// if ( globals->get_tile_mgr()->init() ) { // Load the local scenery data double visibility_meters = fgGetDouble("/environment/visibility-m"); globals->get_tile_mgr()->update( visibility_meters ); } else { SG_LOG( SG_GENERAL, SG_ALERT, "Error in Tile Manager initialization!" ); exit(-1); } // cause refresh of viewer scenery timestamps every 15 seconds... globals->get_event_mgr()->addTask( "FGTileMgr::refresh_view_timestamps()", globals->get_tile_mgr(), &FGTileMgr::refresh_view_timestamps, 15 ); SG_LOG( SG_GENERAL, SG_DEBUG, "Current terrain elevation after tile mgr init " << globals->get_scenery()->get_cur_elev() ); //////////////////////////////////////////////////////////////////// // Initialize the flight model subsystem. //////////////////////////////////////////////////////////////////// fgInitFDM(); // allocates structures so must happen before any of the flight // model or control parameters are set fgAircraftInit(); // In the future this might not be the case. //////////////////////////////////////////////////////////////////// // Initialize the view manager subsystem. //////////////////////////////////////////////////////////////////// fgInitView(); //////////////////////////////////////////////////////////////////// // Create and register the logger. //////////////////////////////////////////////////////////////////// globals->add_subsystem("logger", new FGLogger); #if defined(HAVE_PLIB_PSL) //////////////////////////////////////////////////////////////////// // Create and register the script manager. //////////////////////////////////////////////////////////////////// globals->add_subsystem("scripting", new FGScriptMgr); #endif // HAVE_PLIB_PSL //////////////////////////////////////////////////////////////////// // Create and register the XML GUI. //////////////////////////////////////////////////////////////////// globals->add_subsystem("gui", new NewGUI, SGSubsystemMgr::INIT); //////////////////////////////////////////////////////////////////// // Initialize the local time subsystem. //////////////////////////////////////////////////////////////////// // update the current timezone each 30 minutes globals->get_event_mgr()->addTask( "fgUpdateLocalTime()", &fgUpdateLocalTime, 30*60 ); //////////////////////////////////////////////////////////////////// // Initialize the weather subsystem. //////////////////////////////////////////////////////////////////// // Initialize the weather modeling subsystem #ifdef FG_WEATHERCM // Initialize the WeatherDatabase SG_LOG(SG_GENERAL, SG_INFO, "Creating LocalWeatherDatabase"); sgVec3 position; sgSetVec3( position, current_aircraft.fdm_state->get_Latitude(), current_aircraft.fdm_state->get_Longitude(), current_aircraft.fdm_state->get_Altitude() * SG_FEET_TO_METER ); double init_vis = fgGetDouble("/environment/visibility-m"); FGLocalWeatherDatabase::DatabaseWorkingType working_type; if (!strcmp(fgGetString("/environment/weather/working-type"), "internet")) { working_type = FGLocalWeatherDatabase::use_internet; } else { working_type = FGLocalWeatherDatabase::default_mode; } if ( init_vis > 0 ) { FGLocalWeatherDatabase::theFGLocalWeatherDatabase = new FGLocalWeatherDatabase( position, globals->get_fg_root(), working_type, init_vis ); } else { FGLocalWeatherDatabase::theFGLocalWeatherDatabase = new FGLocalWeatherDatabase( position, globals->get_fg_root(), working_type ); } // cout << theFGLocalWeatherDatabase << endl; // cout << "visibility = " // << theFGLocalWeatherDatabase->getWeatherVisibility() << endl; WeatherDatabase = FGLocalWeatherDatabase::theFGLocalWeatherDatabase; // register the periodic update of the weather globals->get_event_mgr()->add( "weather update", &fgUpdateWeatherDatabase, 30000); #else globals->add_subsystem("environment", new FGEnvironmentMgr); #endif //////////////////////////////////////////////////////////////////// // Initialize the lighting subsystem. //////////////////////////////////////////////////////////////////// globals->add_subsystem("lighting", new FGLight); #ifdef FG_USE_CLOUDS_3D //////////////////////////////////////////////////////////////////// // Initialize the 3D cloud subsystem. //////////////////////////////////////////////////////////////////// if ( fgGetBool("/sim/rendering/clouds3d") ) { static const SGPropertyNode *longitude = fgGetNode("/sim/presets/longitude-deg"); static const SGPropertyNode *latitude = fgGetNode("/sim/presets/latitude-deg"); static const SGPropertyNode *altitude = fgGetNode("/sim/presets/altitude-ft"); SGPath cloud_path(globals->get_fg_root()); #if 0 cloud_path.append("Textures/Sky/scattered.rgba"); SG_LOG(SG_GENERAL, SG_INFO, "Loading CLOUDS3d from: " << cloud_path.c_str()); SGTexture tx; tx.read_rgba_texture(cloud_path.c_str()); if ( !sgCloud3d->Load( tx.texture(), tx.width(), #else cloud_path.append("large.sky"); if ( !sgCloud3d->Load( cloud_path.str(), #endif latitude->getDoubleValue(), longitude->getDoubleValue()) ) { fgSetBool("/sim/rendering/clouds3d", false); SG_LOG(SG_GENERAL, SG_INFO, "CLOUDS3d FAILED: "); } SG_LOG(SG_GENERAL, SG_INFO, "CLOUDS3d Loaded: "); } #endif //////////////////////////////////////////////////////////////////// // Initialise ATC display system //////////////////////////////////////////////////////////////////// SG_LOG(SG_GENERAL, SG_INFO, " ATC Display"); globals->set_ATC_display(new FGATCDisplay); globals->get_ATC_display()->init(); //////////////////////////////////////////////////////////////////// // Initialise the ATC Manager //////////////////////////////////////////////////////////////////// SG_LOG(SG_GENERAL, SG_INFO, " ATC Manager"); globals->set_ATC_mgr(new FGATCMgr); globals->get_ATC_mgr()->init(); //////////////////////////////////////////////////////////////////// // Initialise the AI Manager //////////////////////////////////////////////////////////////////// SG_LOG(SG_GENERAL, SG_INFO, " AI Manager"); globals->set_AI_mgr(new FGAIMgr); globals->get_AI_mgr()->init(); //////////////////////////////////////////////////////////////////// // Initialise the AI Model Manager //////////////////////////////////////////////////////////////////// SG_LOG(SG_GENERAL, SG_INFO, " AI Model Manager"); globals->add_subsystem("ai_model", new FGAIManager); #ifdef ENABLE_AUDIO_SUPPORT //////////////////////////////////////////////////////////////////// // Initialize the sound subsystem. //////////////////////////////////////////////////////////////////// globals->set_soundmgr(new SGSoundMgr); globals->get_soundmgr()->init(); globals->get_soundmgr()->bind(); //////////////////////////////////////////////////////////////////// // Initialize the sound-effects subsystem. //////////////////////////////////////////////////////////////////// globals->add_subsystem("fx", new FGFX); #endif globals->add_subsystem("instrumentation", new FGInstrumentMgr); globals->add_subsystem("systems", new FGSystemMgr); //////////////////////////////////////////////////////////////////// // Initialize the radio stack subsystem. //////////////////////////////////////////////////////////////////// current_radiostack = new FGRadioStack; current_radiostack->init(); current_radiostack->bind(); //////////////////////////////////////////////////////////////////// // Initialize the cockpit subsystem //////////////////////////////////////////////////////////////////// if( fgCockpitInit( ¤t_aircraft )) { // Cockpit initialized ok. } else { SG_LOG( SG_GENERAL, SG_ALERT, "Error in Cockpit initialization!" ); exit(-1); } //////////////////////////////////////////////////////////////////// // Initialize the autopilot subsystem. //////////////////////////////////////////////////////////////////// globals->set_autopilot(new FGAutopilot); globals->get_autopilot()->init(); globals->get_autopilot()->bind(); // FIXME: these should go in the // GUI initialization code, not here. fgAPAdjustInit(); NewTgtAirportInit(); NewHeadingInit(); NewAltitudeInit(); //////////////////////////////////////////////////////////////////// // Initialize I/O subsystem. //////////////////////////////////////////////////////////////////// globals->get_io()->init(); globals->get_io()->bind(); //////////////////////////////////////////////////////////////////// // Add a new 2D panel. //////////////////////////////////////////////////////////////////// string panel_path = fgGetString("/sim/panel/path", "Panels/Default/default.xml"); globals->set_current_panel( fgReadPanel(panel_path) ); if (globals->get_current_panel() == 0) { SG_LOG( SG_INPUT, SG_ALERT, "Error reading new panel from " << panel_path ); } else { SG_LOG( SG_INPUT, SG_INFO, "Loaded new panel from " << panel_path ); globals->get_current_panel()->init(); globals->get_current_panel()->bind(); } //////////////////////////////////////////////////////////////////// // Initialize the default (kludged) properties. //////////////////////////////////////////////////////////////////// fgInitProps(); //////////////////////////////////////////////////////////////////// // Initialize the controls subsystem. //////////////////////////////////////////////////////////////////// globals->get_controls()->init(); globals->get_controls()->bind(); //////////////////////////////////////////////////////////////////// // Initialize the input subsystem. //////////////////////////////////////////////////////////////////// globals->add_subsystem("input", new FGInput); //////////////////////////////////////////////////////////////////// // Initialize the replay subsystem //////////////////////////////////////////////////////////////////// globals->add_subsystem("replay", new FGReplay); //////////////////////////////////////////////////////////////////// // Bind and initialize subsystems. //////////////////////////////////////////////////////////////////// globals->get_subsystem_mgr()->bind(); globals->get_subsystem_mgr()->init(); #ifdef FG_MPLAYER_AS //////////////////////////////////////////////////////////////////// // Initialize multiplayer subsystem //////////////////////////////////////////////////////////////////// globals->set_multiplayer_tx_mgr(new FGMultiplayTxMgr); globals->get_multiplayer_tx_mgr()->init(); globals->set_multiplayer_rx_mgr(new FGMultiplayRxMgr); globals->get_multiplayer_rx_mgr()->init(); #endif //////////////////////////////////////////////////////////////////////// // Initialize the Nasal interpreter. // Do this last, so that the loaded scripts see initialized state //////////////////////////////////////////////////////////////////////// FGNasalSys* nasal = new FGNasalSys(); globals->add_subsystem("nasal", nasal); nasal->init(); //////////////////////////////////////////////////////////////////////// // End of subsystem initialization. //////////////////////////////////////////////////////////////////// SG_LOG( SG_GENERAL, SG_INFO, endl); // Save the initial state for future // reference. globals->saveInitialState(); return true; } void fgReInitSubsystems() { // static const SGPropertyNode *longitude // = fgGetNode("/sim/presets/longitude-deg"); // static const SGPropertyNode *latitude // = fgGetNode("/sim/presets/latitude-deg"); static const SGPropertyNode *altitude = fgGetNode("/sim/presets/altitude-ft"); static const SGPropertyNode *master_freeze = fgGetNode("/sim/freeze/master"); SG_LOG( SG_GENERAL, SG_INFO, "fgReInitSubsystems(): /position/altitude = " << altitude->getDoubleValue() ); bool freeze = master_freeze->getBoolValue(); if ( !freeze ) { fgSetBool("/sim/freeze/master", true); } // Initialize the FDM fgInitFDM(); // allocates structures so must happen before any of the flight // model or control parameters are set fgAircraftInit(); // In the future this might not be the case. // reload offsets from config defaults globals->get_viewmgr()->reinit(); fgInitView(); globals->get_controls()->reset_all(); globals->get_autopilot()->reset(); fgUpdateLocalTime(); // re-init to proper time of day setting fgInitTimeOffset(); if ( !freeze ) { fgSetBool("/sim/freeze/master", false); } }