X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FMain%2Fglobals.cxx;h=d41e00d5f2bff7e3bec088e73ca2cb2df72124d8;hb=16784d590a315e876a7b18076569620640ffbdf6;hp=1de5ecc7aeea40ec7e92f08ceb81aa1cfa282d1b;hpb=8f10fff8dcd59765dbe13b191b1c02ce0c969674;p=flightgear.git diff --git a/src/Main/globals.cxx b/src/Main/globals.cxx index 1de5ecc7a..d41e00d5f 100644 --- a/src/Main/globals.cxx +++ b/src/Main/globals.cxx @@ -27,12 +27,14 @@ #include #include +#include +#include + #include #include #include #include #include -#include #include #include #include @@ -40,22 +42,21 @@ #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 "locale.hxx" @@ -89,7 +90,6 @@ public: } if (r.exists()) { - SG_LOG(SG_IO, SG_DEBUG, "found path:" << aResource << " via /sim/aircraft-dir: " << r.str()); return r; } } @@ -101,7 +101,6 @@ public: 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 @@ -110,51 +109,77 @@ public: } }; +class CurrentAircraftDirProvider : public simgear::ResourceProvider +{ +public: + CurrentAircraftDirProvider() : + simgear::ResourceProvider(simgear::ResourceManager::PRIORITY_HIGH) + { + } + + virtual SGPath resolve(const std::string& aResource, SGPath&) const + { + const char* aircraftDir = fgGetString("/sim/aircraft-dir"); + SGPath p(aircraftDir); + p.append(aResource); + return p.exists() ? p : SGPath(); + } +}; + //////////////////////////////////////////////////////////////////////// // Implementation of FGGlobals. //////////////////////////////////////////////////////////////////////// // global global :-) -FGGlobals *globals; +FGGlobals *globals = NULL; // 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_home( "" ), time_params( NULL ), ephem( NULL ), - mag( NULL ), - matlib( NULL ), route_mgr( NULL ), - ATIS_mgr( NULL ), controls( NULL ), viewmgr( NULL ), commands( SGCommandMgr::instance() ), - acmodel( NULL ), - model_mgr( NULL ), channel_options_list( NULL ), initial_waypoints( NULL ), - scenery( NULL ), - tile_mgr( NULL ), fontcache ( new FGFontCache ), - navlist( NULL ), - loclist( NULL ), - gslist( NULL ), - dmelist( NULL ), - tacanlist( NULL ), - carrierlist( NULL ), channellist( NULL ), - haveUserSettings(false) + haveUserSettings(false), + _chatter_queue(NULL) +{ + SGPropertyNode* root = new SGPropertyNode; + props = SGPropertyNode_ptr(root); + locale = new FGLocale(props); + + simgear::ResourceManager::instance()->addProvider(new AircraftResourceProvider); + simgear::ResourceManager::instance()->addProvider(new CurrentAircraftDirProvider); + initProperties(); +} + +void FGGlobals::initProperties() { - simgear::ResourceManager::instance()->addProvider(new AircraftResourceProvider()); - simgear::PropertyObjectBase::setDefaultRoot(props); + 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 @@ -169,54 +194,71 @@ FGGlobals::~FGGlobals() // 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"); + SGSubsystemRef ai = subsystem_mgr->get_subsystem("ai-model"); if (ai) { + subsystem_mgr->remove("ai-model"); ai->unbind(); - delete ai; + ai.clear(); // ensure AI is deleted now, not at end of this method } - SGSubsystem* sound = subsystem_mgr->remove("sound"); - + subsystem_mgr->shutdown(); - subsystem_mgr->unbind(); - delete subsystem_mgr; + subsystem_mgr->unbind(); + + subsystem_mgr->remove("aircraft-model"); + subsystem_mgr->remove("tile-manager"); + subsystem_mgr->remove("model-manager"); + _tile_mgr.clear(); + + osg::ref_ptr vw(renderer->getViewer()); + if (vw) { + // https://code.google.com/p/flightgear-bugs/issues/detail?id=1291 + // explicitly stop trheading before we delete the renderer or + // viewMgr (which ultimately holds refs to the CameraGroup, and + // GraphicsContext) + vw->stopThreading(); + } - delete renderer; - renderer = NULL; + // don't cancel the pager until after shutdown, since AIModels (and + // potentially others) can queue delete requests on the pager. + if (vw && vw->getDatabasePager()) { + vw->getDatabasePager()->cancel(); + vw->getDatabasePager()->clear(); + } + osgDB::Registry::instance()->clearObjectCache(); + + // renderer touches subsystems during its destruction + set_renderer(NULL); + _scenery.clear(); + _chatter_queue.clear(); + + delete subsystem_mgr; + subsystem_mgr = NULL; // important so ::get_subsystem returns NULL + vw = 0; // don't delete the viewer until now + delete time_params; - delete mag; - delete matlib; + set_matlib(NULL); delete route_mgr; - - delete ATIS_mgr; - - if (controls) - { - controls->unbind(); - delete controls; - } - delete channel_options_list; delete initial_waypoints; - delete scenery; delete fontcache; - - delete navlist; - delete loclist; - delete gslist; - delete dmelist; - delete tacanlist; - delete carrierlist; delete channellist; - delete sound; + simgear::PropertyObjectBase::setDefaultRoot(NULL); + simgear::SGModelLib::resetPropertyRoot(); + delete locale; locale = NULL; + + cleanupListeners(); + + props.clear(); + + delete commands; } - // set the fg_root path -void FGGlobals::set_fg_root (const string &root) { +void FGGlobals::set_fg_root (const std::string &root) { SGPath tmp(root); fg_root = tmp.realpath(); @@ -231,9 +273,10 @@ void FGGlobals::set_fg_root (const string &root) { << fg_root << "'\n***\n***"); } - // remove /sim/fg-root before writing to prevent hijacking + // deliberately not a tied property, for fgValidatePath security + // write-protect to avoid accidents SGPropertyNode *n = fgGetNode("/sim", true); - n->removeChild("fg-root", 0, false); + n->removeChild("fg-root", 0); n = n->getChild("fg-root", 0, true); n->setStringValue(fg_root.c_str()); n->setAttribute(SGPropertyNode::WRITE, false); @@ -242,9 +285,62 @@ void FGGlobals::set_fg_root (const string &root) { simgear::ResourceManager::PRIORITY_DEFAULT); } -void FGGlobals::append_fg_scenery (const string &paths) +// set the fg_home path +void FGGlobals::set_fg_home (const std::string &home) { + SGPath tmp(home); + fg_home = tmp.realpath(); +} + +PathList FGGlobals::get_data_paths() const +{ + PathList r(additional_data_paths); + r.push_back(SGPath(fg_root)); + return r; +} + +PathList FGGlobals::get_data_paths(const std::string& suffix) const +{ + PathList r; + BOOST_FOREACH(SGPath p, get_data_paths()) { + p.append(suffix); + if (p.exists()) { + r.push_back(p); + } + } + + return r; +} + +void FGGlobals::append_data_path(const SGPath& path) +{ + if (!path.exists()) { + SG_LOG(SG_GENERAL, SG_WARN, "adding non-existant data path:" << path); + } + + additional_data_paths.push_back(path); +} + +SGPath FGGlobals::find_data_dir(const std::string& pathSuffix) const +{ + BOOST_FOREACH(SGPath p, additional_data_paths) { + p.append(pathSuffix); + if (p.exists()) { + return p; + } + } + + SGPath rootPath(fg_root); + rootPath.append(pathSuffix); + if (rootPath.exists()) { + return rootPath; + } + + SG_LOG(SG_GENERAL, SG_WARN, "dir not found in any data path:" << pathSuffix); + return SGPath(); +} + +void FGGlobals::append_fg_scenery (const std::string &paths) { -// fg_scenery.clear(); SGPropertyNode* sim = fgGetNode("/sim", true); // find first unused fg-scenery property in /sim @@ -294,27 +390,55 @@ void FGGlobals::append_fg_scenery (const string &paths) SGPropertyNode* n = sim->getChild("fg-scenery", propIndex++, true); n->setStringValue(abspath.str()); n->setAttribute(SGPropertyNode::WRITE, false); + + // temporary fix so these values survive reset + n->setAttribute(SGPropertyNode::PRESERVE, true); } // of path list iteration } +void FGGlobals::clear_fg_scenery() +{ + fg_scenery.clear(); +} + +void FGGlobals::set_catalog_aircraft_path(const SGPath& path) +{ + catalog_aircraft_dir = path; +} + +string_list FGGlobals::get_aircraft_paths() const +{ + string_list r; + if (!catalog_aircraft_dir.isNull()) { + r.push_back(catalog_aircraft_dir.str()); + } + + r.insert(r.end(), fg_aircraft_dirs.begin(), fg_aircraft_dirs.end()); + return r; +} + 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); + SG_LOG(SG_GENERAL, SG_ALERT, "aircraft path not found:" << path); return; } + + SGPath acSubdir(dirPath); + acSubdir.append("Aircraft"); + if (acSubdir.exists()) { + SG_LOG( + SG_GENERAL, + SG_WARN, + "Specified an aircraft-dir with an 'Aircraft' subdirectory:" << dirPath + << ", will instead use child directory:" << acSubdir + ); + dirPath = acSubdir; + } + 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) @@ -335,12 +459,28 @@ 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; } +void FGGlobals::set_renderer(FGRenderer *render) +{ + if (render == renderer) { + return; + } + + delete renderer; + renderer = render; +} + SGSubsystemMgr * FGGlobals::get_subsystem_mgr () const { @@ -350,6 +490,10 @@ FGGlobals::get_subsystem_mgr () const SGSubsystem * FGGlobals::get_subsystem (const char * name) { + if (!subsystem_mgr) { + return NULL; + } + return subsystem_mgr->get_subsystem(name); } @@ -377,70 +521,115 @@ FGGlobals::get_event_mgr () const return event_mgr; } -const SGGeod & +SGGeod FGGlobals::get_aircraft_position() const { - if( acmodel != NULL ) { - SGModelPlacement * mp = acmodel->get3DModel(); - if( mp != NULL ) - return mp->getPosition(); - } - throw sg_exception("Can't get aircraft position", "FGGlobals::get_aircraft_position()" ); + return SGGeod::fromDegFt(positionLon->getDoubleValue(), + positionLat->getDoubleValue(), + positionAlt->getDoubleValue()); } SGVec3d -FGGlobals::get_aircraft_positon_cart() const +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(); +} -// Save the current state as the initial state. -void -FGGlobals::saveInitialState () +SGGeod +FGGlobals::get_view_position() const { - initial_state = new SGPropertyNode(); + return SGGeod::fromDegFt(viewLon->getDoubleValue(), + viewLat->getDoubleValue(), + viewAlt->getDoubleValue()); +} - // 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"); - } +SGVec3d +FGGlobals::get_view_position_cart() const +{ + return SGVec3d::fromGeod(get_view_position()); } +static void treeDumpRefCounts(int depth, SGPropertyNode* nd) +{ + for (int i=0; inChildren(); ++i) { + SGPropertyNode* cp = nd->getChild(i); + if (SGReferenced::count(cp) > 1) { + SG_LOG(SG_GENERAL, SG_INFO, "\t" << cp->getPath() << " refcount:" << SGReferenced::count(cp)); + } + + treeDumpRefCounts(depth + 1, cp); + } +} -// Restore the saved initial state, if any -void -FGGlobals::restoreInitialState () +static void treeClearAliases(SGPropertyNode* nd) { - if ( initial_state == 0 ) { - SG_LOG(SG_GENERAL, SG_ALERT, - "No initial state available to restore!!!"); - return; + if (nd->isAlias()) { + nd->unalias(); } - // 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?)" ); + + for (int i=0; inChildren(); ++i) { + SGPropertyNode* cp = nd->getChild(i); + treeClearAliases(cp); } +} +void +FGGlobals::resetPropertyRoot() +{ + delete locale; + + cleanupListeners(); + + // we don't strictly need to clear these (they will be reset when we + // initProperties again), but trying to reduce false-positives when dumping + // ref-counts. + positionLon.clear(); + positionLat.clear(); + positionAlt.clear(); + viewLon.clear(); + viewLat.clear(); + viewAlt.clear(); + orientPitch.clear(); + orientHeading.clear(); + orientRoll.clear(); + + // clear aliases so ref-counts are accurate when dumped + treeClearAliases(props); + + SG_LOG(SG_GENERAL, SG_INFO, "root props refcount:" << props.getNumRefs()); + treeDumpRefCounts(0, props); + + //BaseStackSnapshot::dumpAll(std::cout); + + props = new SGPropertyNode; + initProperties(); + locale = new FGLocale(props); + + // remove /sim/fg-root before writing to prevent hijacking + SGPropertyNode *n = props->getNode("/sim", true); + n->removeChild("fg-root", 0); + n = n->getChild("fg-root", 0, true); + n->setStringValue(fg_root.c_str()); + n->setAttribute(SGPropertyNode::WRITE, false); +} + +static std::string autosaveName() +{ + std::ostringstream os; + string_list versionParts = simgear::strutils::split(VERSION, "."); + if (versionParts.size() < 2) { + return "autosave.xml"; + } + + os << "autosave_" << versionParts[0] << "_" << versionParts[1] << ".xml"; + return os.str(); } // Load user settings from autosave.xml @@ -450,7 +639,7 @@ 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"); + SGPath autosaveFile = simgear::Dir(dataPath).file(autosaveName()); SGPropertyNode autosave; if (autosaveFile.exists()) { SG_LOG(SG_INPUT, SG_INFO, "Reading user settings from " << autosaveFile.str()); @@ -477,14 +666,14 @@ FGGlobals::saveUserSettings() // don't save settings more than once on shutdown haveUserSettings = false; - SGPath autosaveFile(fgGetString("/sim/fg-home")); - autosaveFile.append( "autosave.xml" ); + SGPath autosaveFile(globals->get_fg_home()); + autosaveFile.append(autosaveName()); 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); + guiErrorMessage("Error writing autosave:", e); } SG_LOG(SG_INPUT, SG_DEBUG, "Finished Saving user settings"); } @@ -516,4 +705,63 @@ void FGGlobals::set_warp_delta( long int d ) fgSetInt("/sim/time/warp-delta", d); } +FGScenery* FGGlobals::get_scenery () const +{ + return _scenery.get(); +} + +void FGGlobals::set_scenery ( FGScenery *s ) +{ + _scenery = s; +} + +FGTileMgr* FGGlobals::get_tile_mgr () const +{ + return _tile_mgr.get(); +} + +void FGGlobals::set_tile_mgr ( FGTileMgr *t ) +{ + _tile_mgr = t; +} + +void FGGlobals::set_matlib( SGMaterialLib *m ) +{ + matlib = m; +} + +FGSampleQueue* FGGlobals::get_chatter_queue() const +{ + return _chatter_queue; +} + +void FGGlobals::set_chatter_queue(FGSampleQueue* queue) +{ + _chatter_queue = queue; +} + +void FGGlobals::addListenerToCleanup(SGPropertyChangeListener* l) +{ + _listeners_to_cleanup.push_back(l); +} + +void FGGlobals::cleanupListeners() +{ + SGPropertyChangeListenerVec::iterator i = _listeners_to_cleanup.begin(); + for (; i != _listeners_to_cleanup.end(); ++i) { + delete *i; + } + _listeners_to_cleanup.clear(); +} + +simgear::pkg::Root* FGGlobals::packageRoot() +{ + return _packageRoot.get(); +} + +void FGGlobals::setPackageRoot(const SGSharedPtr& p) +{ + _packageRoot = p; +} + // end of globals.cxx