#include <string.h> // strcmp()
#include <algorithm>
-#include STL_STRING
+#include <iostream>
+#include <string>
#include <plib/ul.h>
#include <simgear/math/sg_random.h>
+#include <simgear/props/props_io.hxx>
#include <simgear/misc/sgstream.hxx>
#include <simgear/misc/sg_path.hxx>
#include <simgear/scene/material/mat.hxx>
+#include <simgear/sound/soundmgr_openal.hxx>
// #include <Include/general.hxx>
// #include <Airports/simple.hxx>
#include "options.hxx"
#include "util.hxx"
#include "viewmgr.hxx"
+#include <Main/viewer.hxx>
+#include <simgear/version.h>
+using std::string;
+using std::sort;
+using std::cout;
+using std::cerr;
+using std::endl;
-SG_USING_STD(string);
-SG_USING_STD(sort);
-SG_USING_NAMESPACE(std);
-
+#ifndef VERSION
+#define VERSION "CVS "__DATE__
+#endif
#define NEW_DEFAULT_MODEL_HZ 120
FG_OPTIONS_OK = 0,
FG_OPTIONS_HELP = 1,
FG_OPTIONS_ERROR = 2,
- FG_OPTIONS_VERBOSE_HELP = 3,
- FG_OPTIONS_SHOW_AIRCRAFT = 4
+ FG_OPTIONS_EXIT = 3,
+ FG_OPTIONS_VERBOSE_HELP = 4,
+ FG_OPTIONS_SHOW_AIRCRAFT = 5,
+ FG_OPTIONS_SHOW_SOUND_DEVICES = 6
};
static double
atof( const string& str )
{
-
-#ifdef __MWERKS__
- // -dw- if ::atof is called, then we get an infinite loop
- return std::atof( str.c_str() );
-#else
return ::atof( str.c_str() );
-#endif
}
static int
atoi( const string& str )
{
-#ifdef __MWERKS__
- // -dw- if ::atoi is called, then we get an infinite loop
- return std::atoi( str.c_str() );
-#else
return ::atoi( str.c_str() );
-#endif
}
-
/**
* Set a few fail-safe default property values.
*
fgSetDefaults ()
{
// set a possibly independent location for scenery data
- char *envp = ::getenv( "FG_SCENERY" );
+ const char *envp = ::getenv( "FG_SCENERY" );
if ( envp != NULL ) {
// fg_root could be anywhere, so default to environmental
fgSetDouble("/position/altitude-ft", -9999.0);
// Orientation
- fgSetDouble("/orientation/heading-deg", 270);
- fgSetDouble("/orientation/roll-deg", 0);
+ fgSetDouble("/orientation/heading-deg", 9999.0);
+ fgSetDouble("/orientation/roll-deg", 0.0);
fgSetDouble("/orientation/pitch-deg", 0.424);
// Velocities
fgSetDouble("/sim/presets/latitude-deg", 9999.0);
fgSetDouble("/sim/presets/altitude-ft", -9999.0);
- fgSetDouble("/sim/presets/heading-deg", 270);
- fgSetDouble("/sim/presets/roll-deg", 0);
+ fgSetDouble("/sim/presets/heading-deg", 9999.0);
+ fgSetDouble("/sim/presets/roll-deg", 0.0);
fgSetDouble("/sim/presets/pitch-deg", 0.424);
fgSetString("/sim/presets/speed-set", "knots");
fgSetBool("/sim/hud/enable3d", true);
fgSetBool("/sim/hud/visibility", false);
fgSetBool("/sim/panel/visibility", true);
- fgSetBool("/sim/sound/pause", false);
+ fgSetBool("/sim/sound/enabled", true);
+ fgSetBool("/sim/sound/working", true);
// Flight Model options
fgSetString("/sim/flight-model", "jsb");
fgSetBool("/sim/rendering/shading", true);
fgSetBool("/sim/rendering/skyblend", true);
fgSetBool("/sim/rendering/textures", true);
- fgTie( "/sim/rendering/filtering", SGTextureFilterListener::getFilter, SGTextureFilterListener::setFilter, false);
+ fgTie( "/sim/rendering/filtering", SGGetTextureFilter, SGSetTextureFilter, false);
fgSetInt("/sim/rendering/filtering", 1);
fgSetBool("/sim/rendering/wireframe", false);
fgSetBool("/sim/rendering/horizon-effect", false);
if ( fov < FG_FOV_MIN ) { fov = FG_FOV_MIN; }
if ( fov > FG_FOV_MAX ) { fov = FG_FOV_MAX; }
- fgSetDouble("/sim/current-view/field-of-view", fov);
+ fgSetDouble("/sim/view[0]/config/default-field-of-view-deg", fov);
// printf("parse_fov(): result = %.4f\n", fov);
//
// Format is "--protocol=medium,direction,hz,medium_options,..."
//
-// protocol = { native, nmea, garmin, AV400, fgfs, rul, pve, etc. }
+// protocol = { native, nmea, garmin, AV400, AV400Sim, fgfs, rul, pve, etc. }
// medium = { serial, socket, file, etc. }
// direction = { in, out, bi }
// hz = number of times to process channel per second (floating
while ( true ) {
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 );
static int
fgOptWind( const char *arg )
{
- double min_hdg, max_hdg, speed, gust;
+ double min_hdg = 0.0, max_hdg = 0.0, speed = 0.0, gust = 0.0;
if (!parse_wind( arg, &min_hdg, &max_hdg, &speed, &gust)) {
SG_LOG( SG_GENERAL, SG_ALERT, "bad wind value " << arg );
return FG_OPTIONS_ERROR;
return FG_OPTIONS_OK;
}
+static int
+fgOptParking( const char *arg )
+{
+ cerr << "Processing argument " << arg << endl;
+ fgSetString("/sim/presets/parking", arg );
+ fgSetBool ("/sim/presets/parking-requested", true );
+ return FG_OPTIONS_OK;
+}
+
+static int
+fgOptVersion( const char *arg )
+{
+ cerr << "FlightGear version: " << VERSION << endl;
+ cerr << "FG_ROOT=" << globals->get_fg_root() << endl;
+ cerr << "FG_HOME=" << fgGetString("/sim/fg-home") << endl;
+ cerr << "FG_SCENERY=";
+
+ int didsome = 0;
+ string_list scn = globals->get_fg_scenery();
+ for (string_list::const_iterator it = scn.begin(); it != scn.end(); it++)
+ {
+ if (didsome) cerr << ":";
+ didsome++;
+ cerr << *it;
+ }
+ cerr << endl;
+ cerr << "SimGear version: " << SG_STRINGIZE(SIMGEAR_VERSION) << endl;
+ cerr << "PLIB version: " << PLIB_VERSION << endl;
+ return FG_OPTIONS_EXIT;
+}
+
+static int
+fgOptFpe(const char* arg)
+{
+ // Actually handled in bootstrap.cxx
+ return FG_OPTIONS_OK;
+}
+
+static int
+fgOptFgviewer(const char* arg)
+{
+ // Actually handled in bootstrap.cxx
+ return FG_OPTIONS_OK;
+}
+
+
+
static map<string,size_t> fgOptionMap;
/*
value set to the property if has_param is false
func : function called if type==OPTION_FUNC. if has_param is true,
the value is passed to the function as a string, otherwise,
- 0 is passed.
+ s_param is passed.
For OPTION_DOUBLE and OPTION_INT, the parameter value is converted into a
double or an integer and set to the property.
enum OptionType { OPTION_BOOL, OPTION_STRING, OPTION_DOUBLE, OPTION_INT, OPTION_CHANNEL, OPTION_FUNC };
struct OptionDesc {
- char *option;
+ const char *option;
bool has_param;
enum OptionType type;
- char *property;
+ const char *property;
bool b_param;
- char *s_param;
+ const char *s_param;
int (*func)( const char * );
} fgOptionArray[] = {
{"disable-random-objects", false, OPTION_BOOL, "/sim/rendering/random-objects", false, "", 0 },
{"enable-random-objects", false, OPTION_BOOL, "/sim/rendering/random-objects", true, "", 0 },
{"disable-real-weather-fetch", false, OPTION_BOOL, "/environment/params/real-world-weather-fetch", false, "", 0 },
- {"enable-real-weather-fetch", false, OPTION_BOOL, "/environment/params/real-world-weather-fetch", true, "", 0 },
+ {"enable-real-weather-fetch", false, OPTION_BOOL, "/environment/params/real-world-weather-fetch", true, "", 0 },
+ {"metar", true, OPTION_STRING, "/environment/metar/data", false, "", 0 },
{"disable-ai-models", false, OPTION_BOOL, "/sim/ai/enabled", false, "", 0 },
{"enable-ai-models", false, OPTION_BOOL, "/sim/ai/enabled", true, "", 0 },
{"disable-freeze", false, OPTION_BOOL, "/sim/freeze/master", false, "", 0 },
{"enable-hud", false, OPTION_BOOL, "/sim/hud/visibility", true, "", 0 },
{"disable-panel", false, OPTION_BOOL, "/sim/panel/visibility", false, "", 0 },
{"enable-panel", false, OPTION_BOOL, "/sim/panel/visibility", true, "", 0 },
- {"disable-sound", false, OPTION_BOOL, "/sim/sound/pause", true, "", 0 },
- {"enable-sound", false, OPTION_BOOL, "/sim/sound/pause", false, "", 0 },
+ {"disable-sound", false, OPTION_BOOL, "/sim/sound/working", false, "", 0 },
+ {"enable-sound", false, OPTION_BOOL, "/sim/sound/working", true, "", 0 },
+ {"sound-device", true, OPTION_STRING, "/sim/sound/device-name", false, "", 0 },
{"airport", true, OPTION_STRING, "/sim/presets/airport-id", false, "", 0 },
- {"airport-id", true, OPTION_STRING, "/sim/presets/airport-id", false, "", 0 },
{"runway", true, OPTION_FUNC, "", false, "", fgOptRunway },
{"vor", true, OPTION_FUNC, "", false, "", fgOptVOR },
{"ndb", true, OPTION_FUNC, "", false, "", fgOptNDB },
{"carrier", true, OPTION_FUNC, "", false, "", fgOptCarrier },
{"parkpos", true, OPTION_FUNC, "", false, "", fgOptParkpos },
{"fix", true, OPTION_FUNC, "", false, "", fgOptFIX },
- {"offset-distance", true, OPTION_DOUBLE, "/sim/presets/offset-distance", false, "", 0 },
- {"offset-azimuth", true, OPTION_DOUBLE, "/sim/presets/offset-azimuth", false, "", 0 },
+ {"offset-distance", true, OPTION_DOUBLE, "/sim/presets/offset-distance-nm", false, "", 0 },
+ {"offset-azimuth", true, OPTION_DOUBLE, "/sim/presets/offset-azimuth-deg", false, "", 0 },
{"lon", true, OPTION_FUNC, "", false, "", fgOptLon },
{"lat", true, OPTION_FUNC, "", false, "", fgOptLat },
{"altitude", true, OPTION_FUNC, "", false, "", fgOptAltitude },
{"native-gui", true, OPTION_CHANNEL, "", false, "", 0 },
{"opengc", true, OPTION_CHANNEL, "", false, "", 0 },
{"AV400", true, OPTION_CHANNEL, "", false, "", 0 },
+ {"AV400Sim", true, OPTION_CHANNEL, "", false, "", 0 },
{"garmin", true, OPTION_CHANNEL, "", false, "", 0 },
{"nmea", true, OPTION_CHANNEL, "", false, "", 0 },
{"generic", true, OPTION_CHANNEL, "", false, "", 0 },
{"flight-plan", true, OPTION_FUNC, "", false, "", fgOptFlightPlan },
{"config", true, OPTION_FUNC, "", false, "", fgOptConfig },
{"aircraft", true, OPTION_STRING, "/sim/aircraft", false, "", 0 },
+ {"vehicle", true, OPTION_STRING, "/sim/aircraft", false, "", 0 },
{"failure", true, OPTION_FUNC, "", false, "", fgOptFailure },
{"com1", true, OPTION_DOUBLE, "/instrumentation/comm[0]/frequencies/selected-mhz", false, "", 0 },
{"com2", true, OPTION_DOUBLE, "/instrumentation/comm[1]/frequencies/selected-mhz", false, "", 0 },
{"min-status", true, OPTION_STRING, "/sim/aircraft-min-status", false, "all", 0 },
{"livery", true, OPTION_FUNC, "", false, "", fgOptLivery },
{"ai-scenario", true, OPTION_FUNC, "", false, "", fgOptScenario },
+ {"parking-id", true, OPTION_FUNC, "", false, "", fgOptParking },
+ {"version", false, OPTION_FUNC, "", false, "", fgOptVersion },
+ {"enable-fpe", false, OPTION_FUNC, "", false, "", fgOptFpe},
+ {"fgviewer", false, OPTION_FUNC, "", false, "", fgOptFgviewer},
{0}
};
+// Set a property for the --prop: option. Syntax: --prop:[<type>:]<name>=<value>
+// <type> can be "double" etc. but also only the first letter "d".
+// Examples: --prop:alpha=1 --prop:bool:beta=true --prop:d:gamma=0.123
+static bool
+set_property(const string& arg)
+{
+ string::size_type pos = arg.find('=');
+ if (pos == arg.npos || pos == 0 || pos + 1 == arg.size())
+ return false;
+
+ string name = arg.substr(0, pos);
+ string value = arg.substr(pos + 1);
+ string type;
+ pos = name.find(':');
+
+ if (pos != name.npos && pos != 0 && pos + 1 != name.size()) {
+ type = name.substr(0, pos);
+ name = name.substr(pos + 1);
+ }
+ SGPropertyNode *n = fgGetNode(name.c_str(), true);
+
+ bool writable = n->getAttribute(SGPropertyNode::WRITE);
+ if (!writable)
+ n->setAttribute(SGPropertyNode::WRITE, true);
+
+ bool ret = false;
+ if (type.empty())
+ ret = n->setUnspecifiedValue(value.c_str());
+ else if (type == "s" || type == "string")
+ ret = n->setStringValue(value.c_str());
+ else if (type == "d" || type == "double")
+ ret = n->setDoubleValue(strtod(value.c_str(), 0));
+ else if (type == "f" || type == "float")
+ ret = n->setFloatValue(atof(value.c_str()));
+ else if (type == "l" || type == "long")
+ ret = n->setLongValue(strtol(value.c_str(), 0, 0));
+ else if (type == "i" || type == "int")
+ ret = n->setIntValue(atoi(value.c_str()));
+ else if (type == "b" || type == "bool")
+ ret = n->setBoolValue(value == "true" || atoi(value.c_str()) != 0);
+
+ if (!writable)
+ n->setAttribute(SGPropertyNode::WRITE, false);
+ return ret;
+}
+
+
// Parse a single option
static int
parse_option (const string& arg)
return(FG_OPTIONS_VERBOSE_HELP);
} else if ( arg.find( "--show-aircraft") == 0) {
return(FG_OPTIONS_SHOW_AIRCRAFT);
+ } else if ( arg.find( "--show-sound-devices") == 0) {
+ return(FG_OPTIONS_SHOW_SOUND_DEVICES);
} else if ( arg.find( "--prop:" ) == 0 ) {
- string assign = arg.substr(7);
- string::size_type pos = assign.find('=');
- if ( pos == arg.npos || pos == 0 || pos + 1 == assign.size() ) {
- SG_LOG( SG_GENERAL, SG_ALERT, "Bad property assignment: " << arg );
+ if (!set_property(arg.substr(7))) {
+ SG_LOG( SG_GENERAL, SG_ALERT, "Bad property assignment: " << arg );
return FG_OPTIONS_ERROR;
- } else {
- string name = assign.substr(0, pos);
- string value = assign.substr(pos + 1);
- fgSetString(name.c_str(), value.c_str());
}
} else if ( arg.find( "--" ) == 0 ) {
size_t pos = arg.find( '=' );
- string arg_name;
+ string arg_name, arg_value;
if ( pos == string::npos ) {
arg_name = arg.substr( 2 );
} else {
arg_name = arg.substr( 2, pos - 2 );
+ arg_value = arg.substr( pos + 1);
}
map<string,size_t>::iterator it = fgOptionMap.find( arg_name );
if ( it != fgOptionMap.end() ) {
fgSetBool( pt->property, pt->b_param );
break;
case OPTION_STRING:
- if ( pt->has_param && pos != string::npos && pos + 1 < arg.size() ) {
- fgSetString( pt->property, arg.substr( pos + 1 ).c_str() );
- } else if ( !pt->has_param && pos == string::npos ) {
+ if ( pt->has_param && !arg_value.empty() ) {
+ fgSetString( pt->property, arg_value.c_str() );
+ } else if ( !pt->has_param && arg_value.empty() ) {
fgSetString( pt->property, pt->s_param );
} else if ( pt->has_param ) {
SG_LOG( SG_GENERAL, SG_ALERT, "Option '" << arg << "' needs a parameter" );
}
break;
case OPTION_DOUBLE:
- if ( pos != string::npos && pos + 1 < arg.size() ) {
- fgSetDouble( pt->property, atof( arg.substr( pos + 1 ) ) );
+ if ( !arg_value.empty() ) {
+ fgSetDouble( pt->property, atof( arg_value ) );
} else {
SG_LOG( SG_GENERAL, SG_ALERT, "Option '" << arg << "' needs a parameter" );
return FG_OPTIONS_ERROR;
}
break;
case OPTION_INT:
- if ( pos != string::npos && pos + 1 < arg.size() ) {
- fgSetInt( pt->property, atoi( arg.substr( pos + 1 ) ) );
+ if ( !arg_value.empty() ) {
+ fgSetInt( pt->property, atoi( arg_value ) );
} else {
SG_LOG( SG_GENERAL, SG_ALERT, "Option '" << arg << "' needs a parameter" );
return FG_OPTIONS_ERROR;
}
break;
case OPTION_CHANNEL:
- if ( pt->has_param && pos != string::npos && pos + 1 < arg.size() ) {
- add_channel( pt->option, arg.substr( pos + 1 ) );
- } else if ( !pt->has_param && pos == string::npos ) {
+ if ( pt->has_param && !arg_value.empty() ) {
+ add_channel( pt->option, arg_value );
+ } else if ( !pt->has_param && arg_value.empty() ) {
add_channel( pt->option, pt->s_param );
} else if ( pt->has_param ) {
SG_LOG( SG_GENERAL, SG_ALERT, "Option '" << arg << "' needs a parameter" );
}
break;
case OPTION_FUNC:
- if ( pt->has_param && pos != string::npos && pos + 1 < arg.size() ) {
- return pt->func( arg.substr( pos + 1 ).c_str() );
- } else if ( !pt->has_param && pos == string::npos ) {
- return pt->func( 0 );
+ if ( pt->has_param && !arg_value.empty() ) {
+ return pt->func( arg_value.c_str() );
+ } else if ( !pt->has_param && arg_value.empty() ) {
+ return pt->func( pt->s_param );
} else if ( pt->has_param ) {
SG_LOG( SG_GENERAL, SG_ALERT, "Option '" << arg << "' needs a parameter" );
return FG_OPTIONS_ERROR;
verbose = true;
else if (result == FG_OPTIONS_SHOW_AIRCRAFT) {
- fgOptLogLevel( "alert" );
- SGPath path( globals->get_fg_root() );
- path.append("Aircraft");
- fgShowAircraft(path, true);
- exit(0);
+ fgOptLogLevel( "alert" );
+ SGPath path( globals->get_fg_root() );
+ path.append("Aircraft");
+ fgShowAircraft(path, true);
+ exit(0);
+
+ } else if (result == FG_OPTIONS_SHOW_SOUND_DEVICES) {
+ SGSoundMgr smgr;
+
+ smgr.init();
+ string vendor = smgr.get_vendor();
+ string renderer = smgr.get_renderer();
+ cout << renderer << " provided by " << vendor << endl;
+ cout << endl << "No. Device" << endl;
+
+ vector <const char*>devices = smgr.get_available_devices();
+ for (int i=0; i<devices.size(); i++) {
+ cout << i << ". \"" << devices[i] << "\"" << endl;
+ }
+ devices.clear();
+ exit(0);
}
+
+ else if (result == FG_OPTIONS_EXIT)
+ exit(0);
}
} else {
in_options = false;
SG_LOG( SG_GENERAL, SG_INFO, "Processing config file: " << path );
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
int i;
{
// changes should also be reflected in $FG_ROOT/data/options.xml &
// $FG_ROOT/data/Translations/string-default.xml
- const char levels[][20]= {"alpha","beta","early-production","production",0};
+ const char* levels[] = {"alpha","beta","early-production","production"};
- for (unsigned int i=0; i<(sizeof(levels)/sizeof(levels[0])-1);i++)
+ for (size_t i=0; i<(sizeof(levels)/sizeof(levels[0]));i++)
if (strcmp(str,levels[i])==0)
return i;