X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FMain%2Fglobals.cxx;h=683339dcf03d480056b1e0b46b0efda030247cf6;hb=379e7a2fd56efc65887b55e419723903447d462d;hp=b6a932760287f986a205f4b694ac3dced31d1649;hpb=be7e5e49900ce65a023ece8b1954e695b70fa26a;p=flightgear.git diff --git a/src/Main/globals.cxx b/src/Main/globals.cxx index b6a932760..683339dcf 100644 --- a/src/Main/globals.cxx +++ b/src/Main/globals.cxx @@ -2,7 +2,7 @@ // // Written by Curtis Olson, started July 2000. // -// Copyright (C) 2000 Curtis L. Olson - curt@flightgear.org +// Copyright (C) 2000 Curtis L. Olson - http://www.flightgear.org/~curt // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License as @@ -15,22 +15,97 @@ // 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. +// along with this program; if not, write to the Free Software Foundation, +// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. // // $Id$ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include "globals.hxx" -#include "viewmgr.hxx" +#include "locale.hxx" #include "fg_props.hxx" #include "fg_io.hxx" - +class AircraftResourceProvider : public simgear::ResourceProvider +{ +public: + AircraftResourceProvider() : + simgear::ResourceProvider(simgear::ResourceManager::PRIORITY_HIGH) + { + } + + virtual SGPath resolve(const std::string& aResource, SGPath&) const + { + string_list pieces(sgPathBranchSplit(aResource)); + if ((pieces.size() < 3) || (pieces.front() != "Aircraft")) { + return SGPath(); // not an Aircraft path + } + + // test against the aircraft-dir property + const char* aircraftDir = fgGetString("/sim/aircraft-dir"); + string_list aircraftDirPieces(sgPathBranchSplit(aircraftDir)); + if (!aircraftDirPieces.empty() && (aircraftDirPieces.back() == pieces[1])) { + // current aircraft-dir matches resource aircraft + SGPath r(aircraftDir); + for (unsigned int i=2; iget_aircraft_paths()); + string_list::const_iterator it = dirs.begin(); + for (; it != dirs.end(); ++it) { + SGPath p(*it, res); + if (p.exists()) { + SG_LOG(SG_IO, SG_DEBUG, "found path:" << aResource << " in aircraft dir: " << *it); + return p; + } + } // of aircraft path iteration + + return SGPath(); // not found + } +}; + //////////////////////////////////////////////////////////////////////// // Implementation of FGGlobals. //////////////////////////////////////////////////////////////////////// @@ -41,74 +116,228 @@ FGGlobals *globals; // Constructor FGGlobals::FGGlobals() : + props( new SGPropertyNode ), + initial_state( NULL ), + locale( new FGLocale(props) ), + renderer( new FGRenderer ), subsystem_mgr( new SGSubsystemMgr ), event_mgr( new SGEventMgr ), sim_time_sec( 0.0 ), fg_root( "" ), - fg_scenery( "" ), -#if defined(FX) && defined(XMESA) - fullscreen( true ), -#endif - warp( 0 ), - warp_delta( 0 ), + fg_home( "" ), time_params( NULL ), ephem( NULL ), - mag( NULL ), + matlib( NULL ), route_mgr( NULL ), - current_panel( NULL ), - soundmgr( NULL ), - airports( NULL ), - ATC_mgr( NULL ), - ATC_display( NULL ), - AI_mgr( NULL ), + ATIS_mgr( NULL ), controls( NULL ), viewmgr( NULL ), - props( new SGPropertyNode ), - initial_state( NULL ), - locale( NULL ), - commands( new SGCommandMgr ), - model_lib( NULL ), - acmodel( NULL ), - model_mgr( NULL ), + commands( SGCommandMgr::instance() ), channel_options_list( NULL ), + initial_waypoints( NULL ), scenery( NULL ), tile_mgr( NULL ), - io( new FGIO ), - initial_waypoints(0) + fontcache ( new FGFontCache ), + channellist( NULL ), + haveUserSettings(false) { + simgear::ResourceManager::instance()->addProvider(new AircraftResourceProvider()); + simgear::PropertyObjectBase::setDefaultRoot(props); + + positionLon = props->getNode("position/longitude-deg", true); + positionLat = props->getNode("position/latitude-deg", true); + positionAlt = props->getNode("position/altitude-ft", true); + + viewLon = props->getNode("sim/current-view/viewer-lon-deg", true); + viewLat = props->getNode("sim/current-view/viewer-lat-deg", true); + viewAlt = props->getNode("sim/current-view/viewer-elev-ft", true); + + orientPitch = props->getNode("orientation/pitch-deg", true); + orientHeading = props->getNode("orientation/heading-deg", true); + orientRoll = props->getNode("orientation/roll-deg", true); } - // Destructor FGGlobals::~FGGlobals() { - delete subsystem_mgr; - delete event_mgr; - delete initial_state; - delete props; - delete commands; - delete io; - - // make sure only to delete the initial waypoints list if it acually - // still exists. - if (initial_waypoints) + // save user settings (unless already saved) + saveUserSettings(); + + // The AIModels manager performs a number of actions upon + // Shutdown that implicitly assume that other subsystems + // are still operational (Due to the dynamic allocation and + // deallocation of AIModel objects. To ensure we can safely + // shut down all subsystems, make sure we take down the + // AIModels system first. + SGSubsystem* ai = subsystem_mgr->remove("ai-model"); + if (ai) { + ai->unbind(); + delete ai; + } + SGSubsystem* sound = subsystem_mgr->remove("sound"); + + subsystem_mgr->shutdown(); + subsystem_mgr->unbind(); + delete subsystem_mgr; + + delete renderer; + renderer = NULL; + + delete time_params; + delete matlib; + delete route_mgr; + + delete ATIS_mgr; + + delete channel_options_list; delete initial_waypoints; -} + delete scenery; + delete fontcache; + delete channellist; + delete sound; + + delete locale; + locale = NULL; +} // set the fg_root path void FGGlobals::set_fg_root (const string &root) { - fg_root = root; - + SGPath tmp(root); + fg_root = tmp.realpath(); + // append /data to root if it exists - SGPath tmp( fg_root ); tmp.append( "data" ); tmp.append( "version" ); - if ( ulFileExists( tmp.c_str() ) ) { + if ( tmp.exists() ) { + fgGetNode("BAD_FG_ROOT", true)->setStringValue(fg_root); fg_root += "/data"; + fgGetNode("GOOD_FG_ROOT", true)->setStringValue(fg_root); + SG_LOG(SG_GENERAL, SG_ALERT, "***\n***\n*** Warning: changing bad FG_ROOT/--fg-root to '" + << fg_root << "'\n***\n***"); + } + + // remove /sim/fg-root before writing to prevent hijacking + SGPropertyNode *n = fgGetNode("/sim", true); + n->removeChild("fg-root", 0, false); + n = n->getChild("fg-root", 0, true); + n->setStringValue(fg_root.c_str()); + n->setAttribute(SGPropertyNode::WRITE, false); + + simgear::ResourceManager::instance()->addBasePath(fg_root, + simgear::ResourceManager::PRIORITY_DEFAULT); +} + +// set the fg_home path +void FGGlobals::set_fg_home (const string &home) { + SGPath tmp(home); + fg_home = tmp.realpath(); +} + +void FGGlobals::append_fg_scenery (const string &paths) +{ +// fg_scenery.clear(); + SGPropertyNode* sim = fgGetNode("/sim", true); + + // find first unused fg-scenery property in /sim + int propIndex = 0; + while (sim->getChild("fg-scenery", propIndex) != NULL) { + ++propIndex; + } + + BOOST_FOREACH(const SGPath& path, sgPathSplit( paths )) { + SGPath abspath(path.realpath()); + if (!abspath.exists()) { + SG_LOG(SG_GENERAL, SG_WARN, "scenery path not found:" << abspath.str()); + continue; } + + // check for duplicates + string_list::const_iterator ex = std::find(fg_scenery.begin(), fg_scenery.end(), abspath.str()); + if (ex != fg_scenery.end()) { + SG_LOG(SG_GENERAL, SG_INFO, "skipping duplicate add of scenery path:" << abspath.str()); + continue; + } + + simgear::Dir dir(abspath); + SGPath terrainDir(dir.file("Terrain")); + SGPath objectsDir(dir.file("Objects")); + + // this code used to add *either* the base dir, OR add the + // Terrain and Objects subdirs, but the conditional logic was commented + // out, such that all three dirs are added. Unfortunately there's + // no information as to why the change was made. + fg_scenery.push_back(abspath.str()); + + if (terrainDir.exists()) { + fg_scenery.push_back(terrainDir.str()); + } + + if (objectsDir.exists()) { + fg_scenery.push_back(objectsDir.str()); + } + + // insert a marker for FGTileEntry::load(), so that + // FG_SCENERY=A:B becomes list ["A/Terrain", "A/Objects", "", + // "B/Terrain", "B/Objects", ""] + fg_scenery.push_back(""); + + // make scenery dirs available to Nasal + SGPropertyNode* n = sim->getChild("fg-scenery", propIndex++, true); + n->setStringValue(abspath.str()); + n->setAttribute(SGPropertyNode::WRITE, false); + } // of path list iteration +} + +void FGGlobals::append_aircraft_path(const std::string& path) +{ + SGPath dirPath(path); + if (!dirPath.exists()) { + SG_LOG(SG_GENERAL, SG_WARN, "aircraft path not found:" << path); + return; + } + std::string abspath = dirPath.realpath(); + + unsigned int index = fg_aircraft_dirs.size(); + fg_aircraft_dirs.push_back(abspath); + +// make aircraft dirs available to Nasal + SGPropertyNode* sim = fgGetNode("/sim", true); + sim->removeChild("fg-aircraft", index, false); + SGPropertyNode* n = sim->getChild("fg-aircraft", index, true); + n->setStringValue(abspath); + n->setAttribute(SGPropertyNode::WRITE, false); +} + +void FGGlobals::append_aircraft_paths(const std::string& path) +{ + string_list paths = sgPathSplit(path); + for (unsigned int p = 0; pfindPath(branch); +} + +SGPath FGGlobals::resolve_maybe_aircraft_path(const std::string& branch) const +{ + return simgear::ResourceManager::instance()->findPath(branch); +} + +SGPath FGGlobals::resolve_resource_path(const std::string& branch) const +{ + return simgear::ResourceManager::instance() + ->findPath(branch, SGPath(fgGetString("/sim/aircraft-dir"))); +} + +FGRenderer * +FGGlobals::get_renderer () const +{ + return renderer; +} SGSubsystemMgr * FGGlobals::get_subsystem_mgr () const @@ -131,6 +360,14 @@ FGGlobals::add_subsystem (const char * name, subsystem_mgr->add(name, subsystem, type, min_time_sec); } +SGSoundMgr * +FGGlobals::get_soundmgr () const +{ + if (subsystem_mgr) + return (SGSoundMgr*) subsystem_mgr->get_subsystem("sound"); + + return NULL; +} SGEventMgr * FGGlobals::get_event_mgr () const @@ -138,16 +375,64 @@ FGGlobals::get_event_mgr () const return event_mgr; } +SGGeod +FGGlobals::get_aircraft_position() const +{ + return SGGeod::fromDegFt(positionLon->getDoubleValue(), + positionLat->getDoubleValue(), + positionAlt->getDoubleValue()); +} + +SGVec3d +FGGlobals::get_aircraft_position_cart() const +{ + return SGVec3d::fromGeod(get_aircraft_position()); +} + +void FGGlobals::get_aircraft_orientation(double& heading, double& pitch, double& roll) +{ + heading = orientHeading->getDoubleValue(); + pitch = orientPitch->getDoubleValue(); + roll = orientRoll->getDoubleValue(); +} + +SGGeod +FGGlobals::get_view_position() const +{ + return SGGeod::fromDegFt(viewLon->getDoubleValue(), + viewLat->getDoubleValue(), + viewAlt->getDoubleValue()); +} + +SGVec3d +FGGlobals::get_view_position_cart() const +{ + return SGVec3d::fromGeod(get_view_position()); +} // Save the current state as the initial state. void FGGlobals::saveInitialState () { - delete initial_state; initial_state = new SGPropertyNode(); - if (!copyProperties(props, initial_state)) + // copy properties which are READ/WRITEable - but not USERARCHIVEd or PRESERVEd + int checked = SGPropertyNode::READ+SGPropertyNode::WRITE+ + SGPropertyNode::USERARCHIVE+SGPropertyNode::PRESERVE; + int expected = SGPropertyNode::READ+SGPropertyNode::WRITE; + if (!copyProperties(props, initial_state, expected, checked)) SG_LOG(SG_GENERAL, SG_ALERT, "Error saving initial state"); + + // delete various properties from the initial state, since we want to + // preserve their values even if doing a restore + // => Properties should now use the PRESERVE flag to protect their values + // on sim-reset. Remove some specific properties for backward compatibility. + SGPropertyNode* sim = initial_state->getChild("sim"); + SGPropertyNode* cameraGroupNode = sim->getNode("rendering/camera-group"); + if (cameraGroupNode) { + cameraGroupNode->removeChild("camera"); + cameraGroupNode->removeChild("gui"); + } } @@ -160,29 +445,64 @@ FGGlobals::restoreInitialState () "No initial state available to restore!!!"); return; } - - SGPropertyNode *currentPresets = new SGPropertyNode; - SGPropertyNode *targetNode = fgGetNode( "/sim/presets" ); - - // stash the /sim/presets tree - if ( !copyProperties(targetNode, currentPresets) ) { - SG_LOG( SG_GENERAL, SG_ALERT, "Failed to save /sim/presets subtree" ); - } - - if ( copyProperties(initial_state, props) ) { + // copy properties which are READ/WRITEable - but not USERARCHIVEd or PRESERVEd + int checked = SGPropertyNode::READ+SGPropertyNode::WRITE+ + SGPropertyNode::USERARCHIVE+SGPropertyNode::PRESERVE; + int expected = SGPropertyNode::READ+SGPropertyNode::WRITE; + if ( copyProperties(initial_state, props, expected, checked)) { SG_LOG( SG_GENERAL, SG_INFO, "Initial state restored successfully" ); } else { SG_LOG( SG_GENERAL, SG_INFO, "Some errors restoring initial state (read-only props?)" ); } - // recover the /sim/presets tree - if ( !copyProperties(currentPresets, targetNode) ) { - SG_LOG( SG_GENERAL, SG_ALERT, - "Failed to restore /sim/presets subtree" ); +} + +// Load user settings from autosave.xml +void +FGGlobals::loadUserSettings(const SGPath& dataPath) +{ + // remember that we have (tried) to load any existing autsave.xml + haveUserSettings = true; + + SGPath autosaveFile = simgear::Dir(dataPath).file("autosave.xml"); + SGPropertyNode autosave; + if (autosaveFile.exists()) { + SG_LOG(SG_INPUT, SG_INFO, "Reading user settings from " << autosaveFile.str()); + try { + readProperties(autosaveFile.str(), &autosave, SGPropertyNode::USERARCHIVE); + } catch (sg_exception& e) { + SG_LOG(SG_INPUT, SG_WARN, "failed to read user settings:" << e.getMessage() + << "(from " << e.getOrigin() << ")"); + } } + copyProperties(&autosave, globals->get_props()); +} + +// Save user settings in autosave.xml +void +FGGlobals::saveUserSettings() +{ + // only save settings when we have (tried) to load the previous + // settings (otherwise user data was lost) + if (!haveUserSettings) + return; - delete currentPresets; + if (fgGetBool("/sim/startup/save-on-exit")) { + // don't save settings more than once on shutdown + haveUserSettings = false; + + SGPath autosaveFile(globals->get_fg_home()); + autosaveFile.append( "autosave.xml" ); + autosaveFile.create_dir( 0700 ); + SG_LOG(SG_IO, SG_INFO, "Saving user settings to " << autosaveFile.str()); + try { + writeProperties(autosaveFile.str(), globals->get_props(), false, SGPropertyNode::USERARCHIVE); + } catch (const sg_exception &e) { + guiErrorMessage("Error writing autosave.xml: ", e); + } + SG_LOG(SG_INPUT, SG_DEBUG, "Finished Saving user settings"); + } } FGViewer * @@ -191,4 +511,24 @@ FGGlobals::get_current_view () const return viewmgr->get_current_view(); } +long int FGGlobals::get_warp() const +{ + return fgGetInt("/sim/time/warp"); +} + +void FGGlobals::set_warp( long int w ) +{ + fgSetInt("/sim/time/warp", w); +} + +long int FGGlobals::get_warp_delta() const +{ + return fgGetInt("/sim/time/warp-delta"); +} + +void FGGlobals::set_warp_delta( long int d ) +{ + fgSetInt("/sim/time/warp-delta", d); +} + // end of globals.cxx