X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FMain%2Ffg_commands.cxx;h=e5d72f8a923fa5ef0cf1b6082cc96291280b6d11;hb=a704a6208131cad4f12123a72acdb1fb3dc6658f;hp=f9933243d055cf6598b802ea37950e9a181ee085;hpb=87082859d88f9db1bf16d08ede1cb19aa3a251e7;p=flightgear.git diff --git a/src/Main/fg_commands.cxx b/src/Main/fg_commands.cxx index f9933243d..e5d72f8a9 100644 --- a/src/Main/fg_commands.cxx +++ b/src/Main/fg_commands.cxx @@ -19,12 +19,13 @@ #include #include #include +#include #include #include #include +#include +#include -#include -#include #include #include #include @@ -34,9 +35,10 @@ #include #include #include -#include -#include -#include +#include +#include +#include +#include #include "fg_init.hxx" #include "fg_io.hxx" @@ -46,10 +48,10 @@ #include "globals.hxx" #include "logger.hxx" #include "util.hxx" -#include "viewmgr.hxx" #include "main.hxx" -#include
-#include +#include "positioninit.hxx" + +#include using std::string; using std::ifstream; @@ -188,31 +190,7 @@ do_exit (const SGPropertyNode * arg) { SG_LOG(SG_INPUT, SG_INFO, "Program exit requested."); fgSetBool("/sim/signals/exit", true); - - if (fgGetBool("/sim/startup/save-on-exit")) { -#ifdef _WIN32 - char* envp = ::getenv( "APPDATA" ); - if ( envp != NULL ) { - SGPath config( envp ); - config.append( "flightgear.org" ); -#else - if ( homedir != NULL ) { - SGPath config( homedir ); - config.append( ".fgfs" ); -#endif - config.append( "autosave.xml" ); - config.create_dir( 0700 ); - SG_LOG(SG_IO, SG_INFO, "Saving user settings to " << config.str()); - try { - writeProperties(config.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"); - } - } - + globals->saveUserSettings(); fgOSExit(arg->getIntValue("status", 0)); return true; } @@ -228,103 +206,32 @@ do_reset (const SGPropertyNode * arg) return true; } - -/** - * Built-in command: reinitialize one or more subsystems. - * - * subsystem[*]: the name(s) of the subsystem(s) to reinitialize; if - * none is specified, reinitialize all of them. - */ -static bool -do_reinit (const SGPropertyNode * arg) -{ - bool result = true; - - vector subsystems = arg->getChildren("subsystem"); - if (subsystems.size() == 0) { - globals->get_subsystem_mgr()->reinit(); - } else { - for ( unsigned int i = 0; i < subsystems.size(); i++ ) { - const char * name = subsystems[i]->getStringValue(); - SGSubsystem * subsystem = globals->get_subsystem(name); - if (subsystem == 0) { - result = false; - SG_LOG( SG_GENERAL, SG_ALERT, - "Subsystem " << name << " not found" ); - } else { - subsystem->reinit(); - } - } - } - - globals->get_event_mgr()->reinit(); - - return result; -} - -#if 0 - // - // these routines look useful ??? but are never used in the code ??? - // - /** - * Built-in command: suspend one or more subsystems. - * - * subsystem[*] - the name(s) of the subsystem(s) to suspend. + * Built-in command: replay the FDR buffer */ static bool -do_suspend (const SGPropertyNode * arg) +do_replay (const SGPropertyNode * arg) { - bool result = true; - - vector subsystems = arg->getChildren("subsystem"); - for ( unsigned int i = 0; i < subsystems.size(); i++ ) { - const char * name = subsystems[i]->getStringValue(); - SGSubsystem * subsystem = globals->get_subsystem(name); - if (subsystem == 0) { - result = false; - SG_LOG(SG_GENERAL, SG_ALERT, "Subsystem " << name << " not found"); - } else { - subsystem->suspend(); - } - } - return result; + FGReplay *r = (FGReplay *)(globals->get_subsystem( "replay" )); + return r->start(); } /** - * Built-in command: suspend one or more subsystems. - * - * subsystem[*] - the name(s) of the subsystem(s) to suspend. + * Built-in command: pause/unpause the sim */ -static bool -do_resume (const SGPropertyNode * arg) -{ - bool result = true; - - vector subsystems = arg->getChildren("subsystem"); - for ( unsigned int i = 0; i < subsystems.size(); i++ ) { - const char * name = subsystems[i]->getStringValue(); - SGSubsystem * subsystem = globals->get_subsystem(name); - if (subsystem == 0) { - result = false; - SG_LOG(SG_GENERAL, SG_ALERT, "Subsystem " << name << " not found"); - } else { - subsystem->resume(); - } - } - return result; -} - -#endif - static bool do_pause (const SGPropertyNode * arg) { bool paused = fgGetBool("/sim/freeze/master",true) || fgGetBool("/sim/freeze/clock",true); - fgSetBool("/sim/freeze/master",!paused); - fgSetBool("/sim/freeze/clock",!paused); - if (fgGetBool("/sim/freeze/replay-state",false)) - fgSetBool("/sim/replay/disable",true); + if (paused && (fgGetInt("/sim/freeze/replay-state",0)>0)) + { + do_replay(NULL); + } + else + { + fgSetBool("/sim/freeze/master",!paused); + fgSetBool("/sim/freeze/clock",!paused); + } return true; } @@ -402,49 +309,15 @@ do_save (const SGPropertyNode * arg) static bool do_panel_load (const SGPropertyNode * arg) { - string panel_path = - arg->getStringValue("path", fgGetString("/sim/panel/path")); - if (panel_path.empty()) { - return false; + string panel_path = arg->getStringValue("path"); + if (!panel_path.empty()) { + // write to the standard property, which will force a load + fgSetString("/sim/panel/path", panel_path.c_str()); } - FGPanel * new_panel = fgReadPanel(panel_path); - if (new_panel == 0) { - SG_LOG(SG_INPUT, SG_ALERT, - "Error reading new panel from " << panel_path); - return false; - } - SG_LOG(SG_INPUT, SG_INFO, "Loaded new panel from " << panel_path); - globals->get_current_panel()->unbind(); - delete globals->get_current_panel(); - globals->set_current_panel( new_panel ); - globals->get_current_panel()->bind(); return true; } - -/** - * Built-in command: pass a mouse click to the panel. - * - * button: the mouse button number, zero-based. - * is-down: true if the button is down, false if it is up. - * x-pos: the x position of the mouse click. - * y-pos: the y position of the mouse click. - */ -static bool -do_panel_mouse_click (const SGPropertyNode * arg) -{ - if (globals->get_current_panel() != 0) - return globals->get_current_panel() - ->doMouseAction(arg->getIntValue("button"), - arg->getBoolValue("is-down") ? PU_DOWN : PU_UP, - arg->getIntValue("x-pos"), - arg->getIntValue("y-pos")); - else - return false; -} - - /** * Built-in command: (re)load preferences. * @@ -570,6 +443,30 @@ do_tile_cache_reload (const SGPropertyNode * arg) return true; } +/** + * Reload the materials definition + */ + static bool + do_materials_reload (const SGPropertyNode * arg) + { + SG_LOG(SG_INPUT, SG_INFO, "Reloading Materials"); + SGMaterialLib* new_matlib = new SGMaterialLib; + SGPath mpath( globals->get_fg_root() ); + mpath.append( fgGetString("/sim/rendering/materials-file") ); + bool loaded = new_matlib->load(globals->get_fg_root(), + mpath.str(), + globals->get_props()); + + if ( ! loaded ) { + SG_LOG( SG_GENERAL, SG_ALERT, + "Error loading materials file " << mpath.str() ); + return false; + } + + globals->set_matlib(new_matlib); + return true; + } + #if 0 These do_set_(some-environment-parameters) are deprecated and no longer @@ -726,15 +623,18 @@ static bool do_property_assign (const SGPropertyNode * arg) { SGPropertyNode * prop = get_prop(arg); - const SGPropertyNode * prop2 = get_prop2(arg); const SGPropertyNode * value = arg->getNode("value"); if (value != 0) return prop->setUnspecifiedValue(value->getStringValue()); - else if (prop2) - return prop->setUnspecifiedValue(prop2->getStringValue()); else - return false; + { + const SGPropertyNode * prop2 = get_prop2(arg); + if (prop2) + return prop->setUnspecifiedValue(prop2->getStringValue()); + else + return false; + } } @@ -932,6 +832,83 @@ do_property_randomize (const SGPropertyNode * arg) return true; } +/** + * Built-in command: interpolate a property value over time + * + * property: the name of the property value to interpolate. + * value[0..n] any number of constant values to interpolate + * time/rate[0..n] time between each value, number of time elements must + * match those of value elements. Instead of time also rate can + * be used which automatically calculates the time to change + * the property value at the given speed. + * -or- + * property[1..n] any number of target values taken from named properties + * time/rate[0..n] time between each value, number of time elements must + * match those of value elements. Instead of time also rate can + * be used which automatically calculates the time to change + * the property value at the given speed. + */ +static bool +do_property_interpolate (const SGPropertyNode * arg) +{ + SGPropertyNode * prop = get_prop(arg); + + simgear::PropertyList valueNodes = arg->getChildren( "value" ); + simgear::PropertyList timeNodes = arg->getChildren( "time" ); + simgear::PropertyList rateNodes = arg->getChildren( "rate" ); + + if( !timeNodes.empty() && !rateNodes.empty() ) + // mustn't specify time and rate + return false; + + simgear::PropertyList::size_type num_times = timeNodes.empty() + ? rateNodes.size() + : timeNodes.size(); + + boost::scoped_array value; + boost::scoped_array time; + + if( valueNodes.size() > 0 ) { + // must match + if( num_times != valueNodes.size() ) + return false; + + value.reset( new double[valueNodes.size()] ); + for( simgear::PropertyList::size_type n = 0; n < valueNodes.size(); n++ ) { + value[n] = valueNodes[n]->getDoubleValue(); + } + } else { + valueNodes = arg->getChildren("property"); + // must have one more property node + if( valueNodes.size() - 1 != num_times ) + return false; + + value.reset( new double[valueNodes.size()-1] ); + for( simgear::PropertyList::size_type n = 0; n < valueNodes.size()-1; n++ ) { + value[n] = fgGetNode(valueNodes[n+1]->getStringValue(), "/null")->getDoubleValue(); + } + + } + + time.reset( new double[num_times] ); + if( !timeNodes.empty() ) { + for( simgear::PropertyList::size_type n = 0; n < num_times; n++ ) { + time[n] = timeNodes[n]->getDoubleValue(); + } + } else { + for( simgear::PropertyList::size_type n = 0; n < num_times; n++ ) { + double delta = value[n] + - (n > 0 ? value[n - 1] : prop->getDoubleValue()); + time[n] = fabs(delta / rateNodes[n]->getDoubleValue()); + } + } + + ((SGInterpolator*)globals->get_subsystem_mgr() + ->get_group(SGSubsystemMgr::INIT)->get_subsystem("interpolator")) + ->interpolate(prop, num_times, value.get(), time.get() ); + + return true; +} /** * Built-in command: reinit the data logging system based on the @@ -956,7 +933,10 @@ static bool do_dialog_new (const SGPropertyNode * arg) { NewGUI * gui = (NewGUI *)globals->get_subsystem("gui"); - + if (!gui) { + return false; + } + // Note the casting away of const: this is *real*. Doing a // "dialog-apply" command later on will mutate this property node. // I'm not convinced that this isn't the Right Thing though; it @@ -1018,6 +998,20 @@ do_dialog_update (const SGPropertyNode * arg) } } +static bool +do_open_browser (const SGPropertyNode * arg) +{ + string path; + if (arg->hasValue("path")) + path = arg->getStringValue("path"); + else + if (arg->hasValue("url")) + path = arg->getStringValue("url"); + else + return false; + + return openBrowser(path); +} /** * Apply a value in the active XML-configured dialog. @@ -1064,14 +1058,9 @@ static bool do_add_model (const SGPropertyNode * arg) { SGPropertyNode * model = fgGetNode("models", true); - for (int i = 0;; i++) { - if (i < 0) - return false; - if (!model->getChild("model", i, false)) { - model = model->getChild("model", i, true); - break; - } - } + int i; + for (i = 0; model->hasChild("model",i); i++); + model = model->getChild("model", i, true); copyProperties(arg, model); if (model->hasValue("elevation-m")) model->setDoubleValue("elevation-ft", model->getDoubleValue("elevation-m") @@ -1117,6 +1106,12 @@ do_set_cursor (const SGPropertyNode * arg) static bool do_play_audio_sample (const SGPropertyNode * arg) { + SGSoundMgr *smgr = globals->get_soundmgr(); + if (!smgr) { + SG_LOG(SG_GENERAL, SG_WARN, "play-audio-sample: sound-manager not running"); + return false; + } + string path = arg->getStringValue("path"); string file = arg->getStringValue("file"); float volume = arg->getFloatValue("volume"); @@ -1124,7 +1119,6 @@ do_play_audio_sample (const SGPropertyNode * arg) try { static FGSampleQueue *queue = 0; if ( !queue ) { - SGSoundMgr *smgr = globals->get_soundmgr(); queue = new FGSampleQueue(smgr, "chatter"); queue->tie_to_listener(); } @@ -1154,7 +1148,7 @@ do_presets_commit (const SGPropertyNode * arg) // Nasal can trigger this during initial init, which confuses // the logic in ReInitSubsystems, since initial state has not been // saved at that time. Short-circuit everything here. - fgInitPosition(); + flightgear::initPosition(); } return true; @@ -1171,24 +1165,6 @@ do_log_level (const SGPropertyNode * arg) return true; } -/** - * Built-in command: replay the FDR buffer - */ -static bool -do_replay (const SGPropertyNode * arg) -{ - // freeze the fdm, resume from sim pause - fgSetInt( "/sim/freeze/replay-state", 1 ); - fgSetBool("/sim/freeze/master", 0 ); - fgSetBool("/sim/freeze/clock", 0 ); - fgSetDouble( "/sim/replay/time", -1 ); - - // cout << "start = " << r->get_start_time() - // << " end = " << r->get_end_time() << endl; - - return true; -} - /* static bool do_decrease_visibility (const SGPropertyNode * arg) @@ -1229,7 +1205,15 @@ do_load_xml_to_proptree(const SGPropertyNode * arg) std::string icao = arg->getStringValue("icao"); if (icao.empty()) { if (file.isRelative()) { - file = globals->resolve_maybe_aircraft_path(file.str()); + SGPath absPath = globals->resolve_maybe_aircraft_path(file.str()); + if (!absPath.isNull()) + file = absPath; + else + { + SG_LOG(SG_IO, SG_ALERT, "loadxml: Cannot find XML property file '" + << file.str() << "'."); + return false; + } } } else { if (!XMLLoader::findAirportData(icao, file.str(), file)) { @@ -1261,6 +1245,93 @@ do_load_xml_to_proptree(const SGPropertyNode * arg) return true; } +class RemoteXMLRequest : public simgear::HTTP::Request +{ +public: + SGPropertyNode_ptr _complete; + SGPropertyNode_ptr _status; + SGPropertyNode_ptr _failed; + SGPropertyNode_ptr _target; + string propsData; + + RemoteXMLRequest(const std::string& url, SGPropertyNode* targetNode) : + simgear::HTTP::Request(url), + _target(targetNode) + { + } + + void setCompletionProp(SGPropertyNode_ptr p) + { + _complete = p; + } + + void setStatusProp(SGPropertyNode_ptr p) + { + _status = p; + } + + void setFailedProp(SGPropertyNode_ptr p) + { + _failed = p; + } +protected: + virtual void gotBodyData(const char* s, int n) + { + propsData += string(s, n); + } + + virtual void responseComplete() + { + int response = responseCode(); + bool failed = false; + if (response == 200) { + try { + const char* buffer = propsData.c_str(); + readProperties(buffer, propsData.size(), _target, true); + } catch (const sg_exception &e) { + SG_LOG(SG_IO, SG_WARN, "parsing XML from remote, failed: " << e.getFormattedMessage()); + failed = true; + response = 406; // 'not acceptable', anything better? + } + } else { + failed = true; + } + // now the response data is output, signal Nasal / listeners + if (_complete) _complete->setBoolValue(true); + if (_status) _status->setIntValue(response); + if (_failed) _failed->setBoolValue(failed); + } +}; + + +static bool +do_load_xml_from_url(const SGPropertyNode * arg) +{ + std::string url(arg->getStringValue("url")); + if (url.empty()) + return false; + + SGPropertyNode *targetnode; + if (arg->hasValue("targetnode")) + targetnode = fgGetNode(arg->getStringValue("targetnode"), true); + else + targetnode = const_cast(arg)->getNode("data", true); + + RemoteXMLRequest* req = new RemoteXMLRequest(url, targetnode); + +// connect up optional reporting properties + if (arg->hasValue("complete")) + req->setCompletionProp(fgGetNode(arg->getStringValue("complete"), true)); + if (arg->hasValue("failure")) + req->setFailedProp(fgGetNode(arg->getStringValue("failure"), true)); + if (arg->hasValue("status")) + req->setStatusProp(fgGetNode(arg->getStringValue("status"), true)); + + FGHTTPClient::instance()->makeRequest(req); + + return true; +} + /** * An fgcommand to allow saving of xml files via nasal, @@ -1351,63 +1422,6 @@ do_release_cockpit_button (const SGPropertyNode *arg) return true; } - -static SGGeod commandSearchPos(const SGPropertyNode* arg) -{ - if (arg->hasChild("longitude-deg") && arg->hasChild("latitude-deg")) { - return SGGeod::fromDeg(arg->getDoubleValue("longitude-deg"), - arg->getDoubleValue("latitude-deg")); - } - - // use current viewer/aircraft position - return SGGeod::fromDeg(fgGetDouble("/position/longitude-deg"), - fgGetDouble("/position/latitude-deg")); -} - -static bool -do_comm_search(const SGPropertyNode* arg) -{ - SGGeod pos = commandSearchPos(arg); - int khz = static_cast(arg->getDoubleValue("frequency-mhz") * 100.0 + 0.25); - - flightgear::CommStation* sta = flightgear::CommStation::findByFreq(khz, pos, NULL); - if (!sta) { - return true; - } - - SGPropertyNode* result = fgGetNode(arg->getStringValue("result")); - sta->createBinding(result); - return true; -} - -static bool -do_nav_search(const SGPropertyNode* arg) -{ - SGGeod pos = commandSearchPos(arg); - double mhz = arg->getDoubleValue("frequency-mhz"); - - FGNavList* navList = globals->get_navlist(); - string type(arg->getStringValue("type", "vor")); - if (type == "dme") { - navList = globals->get_dmelist(); - } else if (type == "tacan") { - navList = globals->get_tacanlist(); - } - - FGNavRecord* nav = navList->findByFreq(mhz, pos); - if (!nav && (type == "vor")) { - // if we're searching VORs, look for localizers too - nav = globals->get_loclist()->findByFreq(mhz, pos); - } - - if (!nav) { - return true; - } - - SGPropertyNode* result = fgGetNode(arg->getStringValue("result")); - nav->createBinding(result); - return true; -} //////////////////////////////////////////////////////////////////////// // Command setup. @@ -1428,14 +1442,10 @@ static struct { { "nasal", do_nasal }, { "exit", do_exit }, { "reset", do_reset }, - { "reinit", do_reinit }, - { "suspend", do_reinit }, - { "resume", do_reinit }, { "pause", do_pause }, { "load", do_load }, { "save", do_save }, { "panel-load", do_panel_load }, - { "panel-mouse-click", do_panel_mouse_click }, { "preferences-load", do_preferences_load }, { "view-cycle", do_view_cycle }, { "screen-capture", do_screen_capture }, @@ -1455,12 +1465,14 @@ static struct { { "property-scale", do_property_scale }, { "property-cycle", do_property_cycle }, { "property-randomize", do_property_randomize }, + { "property-interpolate", do_property_interpolate }, { "data-logging-commit", do_data_logging_commit }, { "dialog-new", do_dialog_new }, { "dialog-show", do_dialog_show }, { "dialog-close", do_dialog_close }, { "dialog-update", do_dialog_update }, { "dialog-apply", do_dialog_apply }, + { "open-browser", do_open_browser }, { "gui-redraw", do_gui_redraw }, { "add-model", do_add_model }, { "set-cursor", do_set_cursor }, @@ -1474,16 +1486,15 @@ static struct { */ { "loadxml", do_load_xml_to_proptree}, { "savexml", do_save_xml_from_proptree }, + { "xmlhttprequest", do_load_xml_from_url }, { "press-cockpit-button", do_press_cockpit_button }, { "release-cockpit-button", do_release_cockpit_button }, { "dump-scenegraph", do_dump_scene_graph }, { "dump-terrainbranch", do_dump_terrain_branch }, { "print-visible-scene", do_print_visible_scene_info }, { "reload-shaders", do_reload_shaders }, - - { "find-navaid", do_nav_search }, - { "find-comm", do_comm_search }, - + { "reload-materials", do_materials_reload }, + { 0, 0 } // zero-terminated };