#include <simgear/structure/exception.hxx>
#include <simgear/structure/commands.hxx>
#include <simgear/props/props.hxx>
+#include <simgear/props/props_io.hxx>
#include <simgear/structure/event_mgr.hxx>
#include <simgear/sound/soundmgr_openal.hxx>
#include <simgear/timing/sg_time.hxx>
+#include <simgear/io/HTTPMemoryRequest.hxx>
-#include <Cockpit/panel.hxx>
-#include <Cockpit/panel_io.hxx>
-#include <Environment/environment.hxx>
#include <FDM/flight.hxx>
#include <GUI/gui.h>
#include <GUI/new_gui.hxx>
#include <Scenery/scenery.hxx>
#include <Scripting/NasalSys.hxx>
#include <Sound/sample_queue.hxx>
-#include <Time/sunsolver.hxx>
+#include <Airports/xmlloader.hxx>
+#include <Network/HTTPClient.hxx>
+#include <Viewer/viewmgr.hxx>
+#include <Viewer/viewer.hxx>
+#include <Environment/presets.hxx>
#include "fg_init.hxx"
#include "fg_io.hxx"
#include "globals.hxx"
#include "logger.hxx"
#include "util.hxx"
-#include "viewmgr.hxx"
#include "main.hxx"
-#include <Main/viewer.hxx>
+#include "positioninit.hxx"
+
+#include <boost/scoped_array.hpp>
+
+#if FG_HAVE_GPERFTOOLS
+# include <google/profiler.h>
+#endif
using std::string;
using std::ifstream;
using std::ofstream;
-\f
////////////////////////////////////////////////////////////////////////
// Static helper functions.
////////////////////////////////////////////////////////////////////////
}
-\f
+
////////////////////////////////////////////////////////////////////////
// Command implementations.
////////////////////////////////////////////////////////////////////////
{
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;
}
static bool
do_reset (const SGPropertyNode * arg)
{
- doSimulatorReset();
+ fgReInitSubsystems();
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.
+ * Built-in command: replay the FDR buffer
*/
static bool
-do_reinit (const SGPropertyNode * arg)
+do_replay (const SGPropertyNode * arg)
{
- bool result = true;
-
- vector<SGPropertyNode_ptr> 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;
+ FGReplay *r = (FGReplay *)(globals->get_subsystem( "replay" ));
+ return r->start();
}
-#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: pause/unpause the sim
*/
static bool
-do_suspend (const SGPropertyNode * arg)
+do_pause (const SGPropertyNode * arg)
{
- bool result = true;
-
- vector<SGPropertyNode_ptr> 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();
- }
+ bool paused = fgGetBool("/sim/freeze/master",true) || fgGetBool("/sim/freeze/clock",true);
+ if (paused && (fgGetInt("/sim/freeze/replay-state",0)>0))
+ {
+ do_replay(NULL);
}
- return result;
-}
-
-/**
- * Built-in command: suspend one or more subsystems.
- *
- * subsystem[*] - the name(s) of the subsystem(s) to suspend.
- */
-static bool
-do_resume (const SGPropertyNode * arg)
-{
- bool result = true;
-
- vector<SGPropertyNode_ptr> 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();
- }
+ else
+ {
+ fgSetBool("/sim/freeze/master",!paused);
+ fgSetBool("/sim/freeze/clock",!paused);
+ }
+
+ SGPropertyNode_ptr args(new SGPropertyNode);
+ args->setStringValue("id", "sim-pause");
+ if (!paused && fgGetBool("/sim/view-name-popup")) {
+ args->setStringValue("label", "Simulation is paused");
+ globals->get_commands()->execute("show-message", args);
+ } else {
+ globals->get_commands()->execute("clear-message", args);
}
- return result;
+
+ return true;
}
-#endif
-
-
/**
* Built-in command: load flight.
*
}
}
+/**
+ * Built-in command: save flight recorder tape.
+ *
+ */
+static bool
+do_save_tape (const SGPropertyNode * arg)
+{
+ FGReplay* replay = (FGReplay*) globals->get_subsystem("replay");
+ replay->saveTape(arg);
+
+ return true;
+}
+/**
+ * Built-in command: load flight recorder tape.
+ *
+ */
+static bool
+do_load_tape (const SGPropertyNode * arg)
+{
+ FGReplay* replay = (FGReplay*) globals->get_subsystem("replay");
+ replay->loadTape(arg);
+
+ return true;
+}
/**
* Built-in command: (re)load the panel.
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.
*
}
static void
-do_view_next( bool )
+do_view_next(bool do_it)
{
+ // Only switch view if really requested to do so (and not for example while
+ // reset/reposition where /command/view/next is set to false)
+ if( do_it )
+ {
globals->get_current_view()->setHeadingOffset_deg(0.0);
globals->get_viewmgr()->next_view();
+ }
}
static void
-do_view_prev( bool )
+do_view_prev(bool do_it)
{
+ if( do_it )
+ {
globals->get_current_view()->setHeadingOffset_deg(0.0);
globals->get_viewmgr()->prev_view();
+ }
+}
+
+/**
+ * An fgcommand to toggle fullscreen mode.
+ * No parameters.
+ */
+static bool
+do_toggle_fullscreen(const SGPropertyNode *arg)
+{
+ fgOSFullScreen();
+ return true;
}
/**
static bool
do_tile_cache_reload (const SGPropertyNode * arg)
{
- static const SGPropertyNode *master_freeze
- = fgGetNode("/sim/freeze/master");
+ SGPropertyNode *master_freeze = fgGetNode("/sim/freeze/master");
bool freeze = master_freeze->getBoolValue();
SG_LOG(SG_INPUT, SG_INFO, "ReIniting TileCache");
if ( !freeze ) {
- fgSetBool("/sim/freeze/master", true);
+ master_freeze->setBoolValue(true);
}
globals->get_subsystem("tile-manager")->reinit();
if ( !freeze ) {
- fgSetBool("/sim/freeze/master", false);
+ master_freeze->setBoolValue(false);
}
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
+useful/functional - Torsten Dreyer, January 2011
/**
* Set the sea level outside air temperature and assigning that to all
* boundary and aloft environment layers.
dummy.set_dewpoint_degc( dewpoint_degc );
return do_set_dewpoint_sea_level_degc(dummy.get_dewpoint_sea_level_degc());
}
-
-/**
- * Update the lighting manually.
- */
-static bool
-do_timeofday (const SGPropertyNode * arg)
-{
- const string &offset_type = arg->getStringValue("timeofday", "noon");
-
- static const SGPropertyNode *longitude
- = fgGetNode("/position/longitude-deg");
- static const SGPropertyNode *latitude
- = fgGetNode("/position/latitude-deg");
-
- int orig_warp = globals->get_warp();
- SGTime *t = globals->get_time_params();
- time_t cur_time = t->get_cur_time();
- // cout << "cur_time = " << cur_time << endl;
- // cout << "orig_warp = " << orig_warp << endl;
-
- int warp = 0;
- if ( offset_type == "real" ) {
- warp = -orig_warp;
- } 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 );
- }
-
-
- fgSetInt("/sim/time/warp", orig_warp + warp);
-
- return true;
-}
-
+#endif
/**
* Built-in command: toggle a bool property value.
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;
+ }
}
do_property_cycle (const SGPropertyNode * arg)
{
SGPropertyNode * prop = get_prop(arg);
- vector<SGPropertyNode_ptr> values = arg->getChildren("value");
+ std::vector<SGPropertyNode_ptr> values = arg->getChildren("value");
+
+ bool wrap = arg->getBoolValue("wrap", true);
+ // compatible with knob/pick animations
+ int offset = arg->getIntValue("offset", 1);
+
int selection = -1;
int nSelections = values.size();
// Try to find the current selection
for (int i = 0; i < nSelections; i++) {
if (compare_values(prop, values[i])) {
- selection = i + 1;
+ selection = i;
break;
}
}
- // Default or wrap to the first selection
- if (selection < 0 || selection >= nSelections)
+ if (selection < 0) { // default to first selection
selection = 0;
-
+ } else {
+ selection += offset;
+ if (wrap) {
+ selection = (selection + nSelections) % nSelections;
+ } else {
+ SG_CLAMP_RANGE(selection, 0, nSelections - 1);
+ }
+ }
+
prop->setUnspecifiedValue(values[selection]->getStringValue());
return true;
}
return true;
}
+/**
+ * Built-in command: interpolate a property value over time
+ *
+ * property: the name of the property value to interpolate.
+ * type: the interpolation type ("numeric", "color", etc.)
+ * easing: name of easing function (see http://easings.net/)
+ * 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+1] 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);
+ if( !prop )
+ return false;
+
+ simgear::PropertyList time_nodes = arg->getChildren("time");
+ simgear::PropertyList rate_nodes = arg->getChildren("rate");
+
+ if( !time_nodes.empty() && !rate_nodes.empty() )
+ // mustn't specify time and rate
+ return false;
+
+ simgear::PropertyList::size_type num_times = time_nodes.empty()
+ ? rate_nodes.size()
+ : time_nodes.size();
+
+ simgear::PropertyList value_nodes = arg->getChildren("value");
+ if( value_nodes.empty() )
+ {
+ simgear::PropertyList prop_nodes = arg->getChildren("property");
+
+ // must have one more property node
+ if( prop_nodes.size() != num_times + 1 )
+ return false;
+
+ value_nodes.reserve(num_times);
+ for( size_t i = 1; i < prop_nodes.size(); ++i )
+ value_nodes.push_back( fgGetNode(prop_nodes[i]->getStringValue()) );
+ }
+
+ // must match
+ if( value_nodes.size() != num_times )
+ return false;
+
+ double_list deltas;
+ deltas.reserve(num_times);
+
+ if( !time_nodes.empty() )
+ {
+ for( size_t i = 0; i < num_times; ++i )
+ deltas.push_back( time_nodes[i]->getDoubleValue() );
+ }
+ else
+ {
+ for( size_t i = 0; i < num_times; ++i )
+ {
+ // TODO calculate delta based on property type
+ double delta = value_nodes[i]->getDoubleValue()
+ - ( i > 0
+ ? value_nodes[i - 1]->getDoubleValue()
+ : prop->getDoubleValue()
+ );
+ deltas.push_back( fabs(delta / rate_nodes[i]->getDoubleValue()) );
+ }
+ }
+
+ return prop->interpolate
+ (
+ arg->getStringValue("type", "numeric"),
+ value_nodes,
+ deltas,
+ arg->getStringValue("easing", "linear")
+ );
+}
/**
* Built-in command: reinit the data logging system based on the
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
}
}
+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.
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")
return true;
}
-
-/**
- * Set mouse cursor coordinates and cursor shape.
- */
-static bool
-do_set_cursor (const SGPropertyNode * arg)
-{
- if (arg->hasValue("x") || arg->hasValue("y")) {
- SGPropertyNode *mx = fgGetNode("/devices/status/mice/mouse/x", true);
- SGPropertyNode *my = fgGetNode("/devices/status/mice/mouse/y", true);
- int x = arg->getIntValue("x", mx->getIntValue());
- int y = arg->getIntValue("y", my->getIntValue());
- fgWarpMouse(x, y);
- mx->setIntValue(x);
- my->setIntValue(y);
- }
-
- SGPropertyNode *cursor = const_cast<SGPropertyNode *>(arg)->getNode("cursor", true);
- if (cursor->getType() != simgear::props::NONE)
- fgSetMouseCursor(cursor->getIntValue());
-
- cursor->setIntValue(fgGetMouseCursor());
- return true;
-}
-
-
/**
* Built-in command: play an audio message (i.e. a wav file) This is
* fire and forget. Call this once per message and it will get dumped
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");
try {
static FGSampleQueue *queue = 0;
if ( !queue ) {
- SGSoundMgr *smgr = globals->get_soundmgr();
queue = new FGSampleQueue(smgr, "chatter");
queue->tie_to_listener();
}
// 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;
return true;
}
-/**
- * Built-in command: replay the FDR buffer
- */
-static bool
-do_replay (const SGPropertyNode * arg)
-{
- // freeze the master fdm
- fgSetInt( "/sim/freeze/replay-state", 1 );
-
- FGReplay *r = (FGReplay *)(globals->get_subsystem( "replay" ));
-
- fgSetDouble( "/sim/replay/start-time", r->get_start_time() );
- fgSetDouble( "/sim/replay/end-time", r->get_end_time() );
- double duration = fgGetDouble( "/sim/replay/duration" );
- if( duration && duration < (r->get_end_time() - r->get_start_time()) ) {
- fgSetDouble( "/sim/replay/time", r->get_end_time() - duration );
- } else {
- fgSetDouble( "/sim/replay/time", r->get_start_time() );
- }
-
- // cout << "start = " << r->get_start_time()
- // << " end = " << r->get_end_time() << endl;
-
- return true;
-}
-
-
+/*
static bool
do_decrease_visibility (const SGPropertyNode * arg)
{
- double new_value = fgGetDouble("/environment/visibility-m") * 0.9;
- fgSetDouble("/environment/visibility-m", new_value);
- fgDefaultWeatherValue("visibility-m", new_value);
- globals->get_subsystem("environment")->reinit();
-
+ Environment::Presets::VisibilitySingleton::instance()->adjust( 0.9 );
return true;
}
static bool
do_increase_visibility (const SGPropertyNode * arg)
{
- double new_value = fgGetDouble("/environment/visibility-m") * 1.1;
- fgSetDouble("/environment/visibility-m", new_value);
- fgDefaultWeatherValue("visibility-m", new_value);
- globals->get_subsystem("environment")->reinit();
-
+ Environment::Presets::VisibilitySingleton::instance()->adjust( 1.1 );
return true;
}
-
+*/
/**
* An fgcommand to allow loading of xml files via nasal,
* the xml file's structure will be made available within
if (file.extension() != "xml")
file.concat(".xml");
-
- if (file.isRelative()) {
- file = globals->resolve_maybe_aircraft_path(file.str());
+
+ std::string icao = arg->getStringValue("icao");
+ if (icao.empty()) {
+ if (file.isRelative()) {
+ 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)) {
+ SG_LOG(SG_IO, SG_INFO, "loadxml: failed to find airport data for "
+ << file.str() << " at ICAO:" << icao);
+ return false;
+ }
}
-
+
if (!fgValidatePath(file.c_str(), false)) {
SG_LOG(SG_IO, SG_ALERT, "loadxml: reading '" << file.str() << "' denied "
"(unauthorized access)");
return true;
}
+class RemoteXMLRequest:
+ public simgear::HTTP::MemoryRequest
+{
+public:
+ SGPropertyNode_ptr _complete;
+ SGPropertyNode_ptr _status;
+ SGPropertyNode_ptr _failed;
+ SGPropertyNode_ptr _target;
+
+ RemoteXMLRequest(const std::string& url, SGPropertyNode* targetNode) :
+ simgear::HTTP::MemoryRequest(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 onFail()
+ {
+ SG_LOG(SG_IO, SG_INFO, "network level failure in RemoteXMLRequest");
+ if (_failed) {
+ _failed->setBoolValue(true);
+ }
+ }
+
+ virtual void onDone()
+ {
+ int response = responseCode();
+ bool failed = false;
+ if (response == 200) {
+ try {
+ const char* buffer = responseBody().c_str();
+ readProperties(buffer, responseBody().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) _failed->setBoolValue(true);
+ }
+};
+
+
+static bool
+do_load_xml_from_url(const SGPropertyNode * arg)
+{
+ FGHTTPClient* http = static_cast<FGHTTPClient*>(globals->get_subsystem("http"));
+ if (!http) {
+ SG_LOG(SG_IO, SG_ALERT, "xmlhttprequest: HTTP client not running");
+ return false;
+ }
+
+ 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<SGPropertyNode *>(arg)->getNode("data", true);
+
+ RemoteXMLRequest* req = new RemoteXMLRequest(url, targetnode);
+
+ if (arg->hasChild("body"))
+ req->setBodyData(arg->getChild("body"));
+
+// 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));
+
+ http->makeRequest(req);
+ return true;
+}
+
/**
* An fgcommand to allow saving of xml files via nasal,
return true;
}
+// Optional profiling commands using gperftools:
+// http://code.google.com/p/gperftools/
+
+#if !FG_HAVE_GPERFTOOLS
+static void
+no_profiling_support()
+{
+ SG_LOG
+ (
+ SG_GENERAL,
+ SG_WARN,
+ "No profiling support! Install gperftools and reconfigure/rebuild fgfs."
+ );
+}
+#endif
+
+static bool
+do_profiler_start(const SGPropertyNode *arg)
+{
+#if FG_HAVE_GPERFTOOLS
+ const char *filename = arg->getStringValue("filename", "fgfs.profile");
+ ProfilerStart(filename);
+ return true;
+#else
+ no_profiling_support();
+ return false;
+#endif
+}
+
+static bool
+do_profiler_stop(const SGPropertyNode *arg)
+{
+#if FG_HAVE_GPERFTOOLS
+ ProfilerStop();
+ return true;
+#else
+ no_profiling_support();
+ return false;
+#endif
+}
+
////////////////////////////////////////////////////////////////////////
// Command setup.
{ "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 },
+ { "save-tape", do_save_tape },
+ { "load-tape", do_load_tape },
{ "panel-load", do_panel_load },
- { "panel-mouse-click", do_panel_mouse_click },
{ "preferences-load", do_preferences_load },
+ { "toggle-fullscreen", do_toggle_fullscreen },
{ "view-cycle", do_view_cycle },
{ "screen-capture", do_screen_capture },
{ "hires-screen-capture", do_hires_screen_capture },
{ "tile-cache-reload", do_tile_cache_reload },
+ /*
{ "set-sea-level-air-temp-degc", do_set_sea_level_degc },
{ "set-outside-air-temp-degc", do_set_oat_degc },
{ "set-dewpoint-sea-level-air-temp-degc", do_set_dewpoint_sea_level_degc },
{ "set-dewpoint-temp-degc", do_set_dewpoint_degc },
- { "timeofday", do_timeofday },
+ */
{ "property-toggle", do_property_toggle },
{ "property-assign", do_property_assign },
{ "property-adjust", do_property_adjust },
{ "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 },
{ "play-audio-sample", do_play_audio_sample },
{ "presets-commit", do_presets_commit },
{ "log-level", do_log_level },
{ "replay", do_replay },
+ /*
{ "decrease-visibility", do_decrease_visibility },
{ "increase-visibility", do_increase_visibility },
+ */
{ "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 },
+ { "reload-materials", do_materials_reload },
+
+ { "profiler-start", do_profiler_start },
+ { "profiler-stop", do_profiler_stop },
+
{ 0, 0 } // zero-terminated
};
typedef bool (*dummy)();
fgTie( "/command/view/next", dummy(0), do_view_next );
fgTie( "/command/view/prev", dummy(0), do_view_prev );
+
+ globals->get_props()->setValueReadOnly( "/sim/debug/profiler-available",
+ bool(FG_HAVE_GPERFTOOLS) );
}
// end of fg_commands.cxx