1 // options.cxx -- class to handle command line options
3 // Written by Curtis Olson, started April 1998.
5 // Copyright (C) 1998 Curtis L. Olson - curt@me.umn.edu
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License as
9 // published by the Free Software Foundation; either version 2 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful, but
13 // WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 // General Public License for more details.
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
28 #if defined(FX) && defined(XMESA)
29 bool global_fullscreen = true;
32 #include <simgear/compiler.h>
34 #include <math.h> // rint()
36 #include <stdlib.h> // atof(), atoi()
41 #include <simgear/constants.h>
42 #include <simgear/debug/logstream.hxx>
43 #include <simgear/misc/fgstream.hxx>
44 #include <simgear/misc/props.hxx>
45 #include <simgear/timing/sg_time.hxx>
47 #include <Include/general.hxx>
48 #include <Airports/simple.hxx>
49 #include <Cockpit/cockpit.hxx>
50 #include <FDM/flight.hxx>
51 #include <FDM/UIUCModel/uiuc_aircraftdir.h>
53 # include <NetworkOLK/network.h>
56 #include "fg_init.hxx"
57 #include "globals.hxx"
58 #include "options.hxx"
61 FG_USING_NAMESPACE(std);
64 extern void fgReshape( int width, int height );
67 atof( const string& str )
71 // -dw- if ::atof is called, then we get an infinite loop
72 return std::atof( str.c_str() );
74 return ::atof( str.c_str() );
79 atoi( const string& str )
82 // -dw- if ::atoi is called, then we get an infinite loop
83 return std::atoi( str.c_str() );
85 return ::atoi( str.c_str() );
90 // Defined the shared options class here
91 // FGOptions current_options;
93 #define PROP(name) (globals->get_props()->getValue(name, true))
97 FGOptions::FGOptions()
99 char* envp = ::getenv( "FG_ROOT" );
101 if ( envp != NULL ) {
102 // fg_root could be anywhere, so default to environmental
103 // variable $FG_ROOT if it is set.
104 globals->set_fg_root(envp);
106 // Otherwise, default to a random compiled-in location if
107 // $FG_ROOT is not set. This can still be overridden from the
108 // command line or a config file.
111 globals->set_fg_root("\\FlightGear");
112 #elif defined( macintosh )
113 globals->set_fg_root("");
115 globals->set_fg_root(PKGLIBDIR);
119 // set a possibly independent location for scenery data
120 envp = ::getenv( "FG_SCENERY" );
122 if ( envp != NULL ) {
123 // fg_root could be anywhere, so default to environmental
124 // variable $FG_ROOT if it is set.
125 globals->set_fg_scenery(envp);
127 // Otherwise, default to Scenery being in $FG_ROOT/Scenery
128 globals->set_fg_scenery("");
135 // These are all deprecated, and will
136 // be removed gradually.
137 airport_id = PROP("/sim/startup/airport-id");
138 lon = PROP("/position/longitude");
139 lat = PROP("/position/latitude");
140 altitude = PROP("/position/altitude");
141 heading = PROP("/orientation/heading");
142 roll = PROP("/orientation/roll");
143 pitch = PROP("/orientation/pitch");
144 speedset = PROP("/sim/startup/speed-set");
145 uBody = PROP("/velocities/uBody");
146 vBody = PROP("/velocities/vBody");
147 wBody = PROP("/velocities/wBody");
148 vNorth = PROP("/velocities/speed-north");
149 vEast = PROP("/velocities/speed-east");
150 vDown = PROP("/velocities/speed-down");
151 vkcas = PROP("/velocities/knots");
152 mach = PROP("/velocities/mach");
153 game_mode = PROP("/sim/startup/game-mode");
154 splash_screen = PROP("/sim/startup/splash-screen");
155 intro_music = PROP("/sim/startup/intro-music");
156 mouse_pointer = PROP("/sim/startup/mouse-pointer");
157 control_mode = PROP("/sim/control-mode");
158 auto_coordination = PROP("/sim/auto-coordination");
159 hud_status = PROP("/sim/hud/visibility");
160 panel_status = PROP("/sim/panel/visibility");
161 sound = PROP("/sim/sound");
162 anti_alias_hud = PROP("/sim/hud/antialiased");
163 flight_model = PROP("/sim/flight-model");
164 aircraft = PROP("/sim/aircraft");
165 model_hz = PROP("/sim/model-hz");
166 speed_up = PROP("/sim/speed-up");
167 trim = PROP("/sim/startup/trim");
168 fog = PROP("/sim/rendering/fog");
169 clouds = PROP("/environment/clouds/enabled");
170 clouds_asl = PROP("/environments/clouds/altitude");
171 fullscreen = PROP("/sim/startup/fullscreen");
172 shading = PROP("/sim/rendering/shading");
173 skyblend = PROP("/sim/rendering/skyblend");
174 textures = PROP("/sim/rendering/textures");
175 wireframe = PROP("/sim/rendering/wireframe");
176 xsize = PROP("/sim/startup/xsize");
177 ysize = PROP("/sim/startup/ysize");
178 bpp = PROP("/sim/rendering/bits-per-pixel");
179 view_mode = PROP("/sim/view-mode");
180 default_view_offset = PROP("/sim/startup/view-offset");
181 visibility = PROP("/environment/visibility");
182 units = PROP("/sim/startup/units");
183 tris_or_culled = PROP("/sim/hud/frame-stat-type");
184 time_offset = PROP("/sim/startup/time-offset");
185 time_offset_type = PROP("/sim/startup/time-offset-type");
186 network_olk = PROP("/sim/networking/network-olk");
187 net_id = PROP("/sim/networking/call-sign");
192 * Set a few fail-safe default property values.
194 * These should all be set in $FG_ROOT/preferences.xml, but just
195 * in case, we provide some initial sane values here. This method
196 * should be invoked *before* reading any init files.
199 FGOptions::set_default_props ()
201 SGPropertyNode * props = globals->get_props();
203 // Position (Globe, AZ)
204 props->setDoubleValue("/position/longitude", -110.6642444);
205 props->setDoubleValue("/position/latitude", 33.3528917);
206 props->setDoubleValue("/position/altitude", -9999.0);
209 props->setDoubleValue("/orientation/heading", 270);
210 props->setDoubleValue("/orientation/roll", 0);
211 props->setDoubleValue("/orientation/pitch", 0.424);
214 props->setStringValue("/sim/startup/speed-set", "knots");
215 props->setDoubleValue("/velocities/uBody", 0.0);
216 props->setDoubleValue("/velocities/vBody", 0.0);
217 props->setDoubleValue("/velocities/wBody", 0.0);
218 props->setDoubleValue("/velocities/speed-north", 0.0);
219 props->setDoubleValue("/velocities/speed-east", 0.0);
220 props->setDoubleValue("/velocities/speed-down", 0.0);
221 props->setDoubleValue("/velocities/airspeed", 0.0);
222 props->setDoubleValue("/velocities/mach", 0.0);
225 props->setBoolValue("/sim/startup/game-mode", false);
226 props->setBoolValue("/sim/startup/splash-screen", true);
227 props->setBoolValue("/sim/startup/intro-music", true);
228 props->setStringValue("/sim/startup/mouse-pointer", "disabled");
229 props->setStringValue("/sim/control-mode", "joystick");
230 props->setBoolValue("/sim/auto-coordination", false);
233 props->setBoolValue("/sim/hud/visibility", false);
234 props->setBoolValue("/sim/panel/visibility", true);
235 props->setBoolValue("/sim/sound", true);
236 props->setBoolValue("/sim/hud/antialiased", false);
238 // Flight Model options
239 props->setStringValue("/sim/flight-model", "larcsim");
240 props->setStringValue("/sim/aircraft", "c172");
241 props->setIntValue("/sim/model-hz", NEW_DEFAULT_MODEL_HZ);
242 props->setIntValue("/sim/speed-up", 1);
243 props->setBoolValue("/sim/startup/trim", false);
246 props->setStringValue("/sim/rendering/fog", "nicest");
247 props->setBoolValue("/environment/clouds/enabled", true);
248 props->setDoubleValue("/environment/clouds/altitude", 5000);
249 props->setBoolValue("/sim/startup/fullscreen", false);
250 props->setBoolValue("/sim/rendering/shading", true);
251 props->setBoolValue("/sim/rendering/skyblend", true);
252 props->setBoolValue("/sim/rendering/textures", true);
253 props->setBoolValue("/sim/rendering/wireframe", false);
254 props->setIntValue("/sim/startup/xsize", 800);
255 props->setIntValue("/sim/startup/ysize", 600);
256 props->setIntValue("/sim/rendering/bits-per-pixel", 16);
257 props->setIntValue("/sim/view-mode", (int)FG_VIEW_PILOT);
258 props->setDoubleValue("/sim/startup/view-offset", 0);
259 props->setDoubleValue("/environment/visibility", 20000);
262 props->setStringValue("/sim/startup/units", "feet");
263 props->setStringValue("/sim/hud/frame-stat-type", "tris");
266 props->setIntValue("/sim/startup/time-offset", 0);
268 props->setBoolValue("/sim/networking/network-olk", false);
269 props->setStringValue("/sim/networking/call-sign", "Johnny");
273 FGOptions::toggle_panel() {
274 SGPropertyNode * props = globals->get_props();
275 bool freeze = globals->get_freeze();
278 globals->set_freeze(true);
280 if(props->getBoolValue("/sim/panel/visibility"))
281 props->setBoolValue("/sim/panel/visibility", false);
283 props->setBoolValue("/sim/panel/visibility", true);
285 fgReshape(props->getIntValue("/sim/startup/xsize"),
286 props->getIntValue("/sim/startup/ysize"));
289 globals->set_freeze( false );
293 FGOptions::parse_time(const string& time_in) {
294 char *time_str, num[256];
295 double hours, minutes, seconds;
300 time_str = (char *)time_in.c_str();
302 // printf("parse_time(): %s\n", time_str);
305 if ( strlen(time_str) ) {
306 if ( time_str[0] == '+' ) {
309 } else if ( time_str[0] == '-' ) {
314 // printf("sign = %d\n", sign);
317 if ( strlen(time_str) ) {
319 while ( (time_str[0] != ':') && (time_str[0] != '\0') ) {
320 num[i] = time_str[0];
324 if ( time_str[0] == ':' ) {
329 // printf("hours = %.2lf\n", hours);
335 if ( strlen(time_str) ) {
337 while ( (time_str[0] != ':') && (time_str[0] != '\0') ) {
338 num[i] = time_str[0];
342 if ( time_str[0] == ':' ) {
347 // printf("minutes = %.2lf\n", minutes);
349 result += minutes / 60.0;
353 if ( strlen(time_str) ) {
355 while ( (time_str[0] != ':') && (time_str[0] != '\0') ) {
356 num[i] = time_str[0];
362 // printf("seconds = %.2lf\n", seconds);
364 result += seconds / 3600.0;
367 return(sign * result);
371 long int FGOptions::parse_date( const string& date)
374 char * date_str, num[256];
376 // initialize to zero
383 gmt.tm_isdst = 0; // ignore daylight savings time for the moment
384 date_str = (char *)date.c_str();
386 if ( strlen(date_str) ) {
388 while ( (date_str[0] != ':') && (date_str[0] != '\0') ) {
389 num[i] = date_str[0];
393 if ( date_str[0] == ':' ) {
397 gmt.tm_year = atoi(num) - 1900;
400 if ( strlen(date_str) ) {
402 while ( (date_str[0] != ':') && (date_str[0] != '\0') ) {
403 num[i] = date_str[0];
407 if ( date_str[0] == ':' ) {
411 gmt.tm_mon = atoi(num) -1;
414 if ( strlen(date_str) ) {
416 while ( (date_str[0] != ':') && (date_str[0] != '\0') ) {
417 num[i] = date_str[0];
421 if ( date_str[0] == ':' ) {
425 gmt.tm_mday = atoi(num);
428 if ( strlen(date_str) ) {
430 while ( (date_str[0] != ':') && (date_str[0] != '\0') ) {
431 num[i] = date_str[0];
435 if ( date_str[0] == ':' ) {
439 gmt.tm_hour = atoi(num);
442 if ( strlen(date_str) ) {
444 while ( (date_str[0] != ':') && (date_str[0] != '\0') ) {
445 num[i] = date_str[0];
449 if ( date_str[0] == ':' ) {
453 gmt.tm_min = atoi(num);
456 if ( strlen(date_str) ) {
458 while ( (date_str[0] != ':') && (date_str[0] != '\0') ) {
459 num[i] = date_str[0];
463 if ( date_str[0] == ':' ) {
467 gmt.tm_sec = atoi(num);
469 time_t theTime = sgTimeGetGMT( gmt.tm_year, gmt.tm_mon, gmt.tm_mday,
470 gmt.tm_hour, gmt.tm_min, gmt.tm_sec );
471 //printf ("Date is %s\n", ctime(&theTime));
472 //printf ("in seconds that is %d\n", theTime);
478 /// parse degree in the form of [+/-]hhh:mm:ss
480 FGOptions::parse_degree( const string& degree_str) {
481 double result = parse_time( degree_str );
483 // printf("Degree = %.4f\n", result);
489 // parse time offset command line option
491 FGOptions::parse_time_offset( const string& time_str) {
494 // printf("time offset = %s\n", time_str);
497 result = (int)rint(parse_time(time_str) * 3600.0);
499 result = (int)(parse_time(time_str) * 3600.0);
502 // printf("parse_time_offset(): %d\n", result);
508 // Parse --fdm=abcdefg type option
510 FGOptions::parse_fdm( const string& fm ) const {
511 // cout << "fdm = " << fm << endl;
514 return FGInterface::FG_ADA;
515 } else if ( fm == "balloon" ) {
516 return FGInterface::FG_BALLOONSIM;
517 } else if ( fm == "external" ) {
518 return FGInterface::FG_EXTERNAL;
519 } else if ( fm == "jsb" ) {
520 return FGInterface::FG_JSBSIM;
521 } else if ( (fm == "larcsim") || (fm == "LaRCsim") ) {
522 return FGInterface::FG_LARCSIM;
523 } else if ( fm == "magic" ) {
524 return FGInterface::FG_MAGICCARPET;
526 FG_LOG( FG_GENERAL, FG_ALERT, "Unknown fdm = " << fm );
530 // we'll never get here, but it makes the compiler happy.
535 // Parse --fov=x.xx type option
537 FGOptions::parse_fov( const string& arg ) {
538 double fov = atof(arg);
540 if ( fov < FG_FOV_MIN ) { fov = FG_FOV_MIN; }
541 if ( fov > FG_FOV_MAX ) { fov = FG_FOV_MAX; }
543 globals->get_props()->setDoubleValue("/sim/field-of-view", fov);
545 // printf("parse_fov(): result = %.4f\n", fov);
551 // Parse I/O channel option
553 // Format is "--protocol=medium,direction,hz,medium_options,..."
555 // protocol = { native, nmea, garmin, fgfs, rul, pve, etc. }
556 // medium = { serial, socket, file, etc. }
557 // direction = { in, out, bi }
558 // hz = number of times to process channel per second (floating
559 // point values are ok.
561 // Serial example "--nmea=serial,dir,hz,device,baud" where
563 // device = OS device name of serial line to be open()'ed
564 // baud = {300, 1200, 2400, ..., 230400}
566 // Socket exacmple "--native=socket,dir,hz,machine,port,style" where
568 // machine = machine name or ip address if client (leave empty if server)
569 // port = port, leave empty to let system choose
570 // style = tcp or udp
572 // File example "--garmin=file,dir,hz,filename" where
574 // filename = file system file name
577 FGOptions::parse_channel( const string& type, const string& channel_str ) {
578 // cout << "Channel string = " << channel_str << endl;
580 globals->get_channel_options_list().push_back( type + "," + channel_str );
586 // Parse --wp=ID[,alt]
587 bool FGOptions::parse_wp( const string& arg ) {
591 int pos = arg.find( "@" );
592 if ( pos != string::npos ) {
593 id = arg.substr( 0, pos );
594 alt_str = arg.substr( pos + 1 );
595 // cout << "id str = " << id << " alt str = " << alt_str << endl;
596 alt = atof( alt_str.c_str() );
597 if ( globals->get_props()->getStringValue("/sim/startup/units")
599 alt *= FEET_TO_METER;
606 if ( fgFindAirportID( id, &a ) ) {
607 SGWayPoint wp( a.longitude, a.latitude, alt, SGWayPoint::WGS84, id );
608 globals->get_route()->add_waypoint( wp );
617 // Parse --flight-plan=[file]
618 bool FGOptions::parse_flightplan(const string& arg)
620 fg_gzifstream infile(arg.c_str());
626 #ifdef GETLINE_NEEDS_TERMINATOR
627 getline( infile, line, '\n' );
628 #elif defined( macintosh )
629 getline( infile, line, '\r' );
631 getline( infile, line );
633 if ( infile.eof() ) {
643 // Parse a single option
644 int FGOptions::parse_option( const string& arg ) {
645 SGPropertyNode * props = globals->get_props();
647 if ( (arg == "--help") || (arg == "-h") ) {
648 // help/usage request
649 return(FG_OPTIONS_HELP);
650 } else if ( arg == "--disable-game-mode") {
651 props->setBoolValue("/sim/startup/game-mode", false);
652 } else if ( arg == "--enable-game-mode" ) {
653 props->setBoolValue("/sim/startup/game-mode", true);
654 } else if ( arg == "--disable-splash-screen" ) {
655 props->setBoolValue("/sim/startup/splash-screen", false);
656 } else if ( arg == "--enable-splash-screen" ) {
657 props->setBoolValue("/sim/startup/splash-screen", true);
658 } else if ( arg == "--disable-intro-music" ) {
659 props->setBoolValue("/sim/startup/intro-music", false);
660 } else if ( arg == "--enable-intro-music" ) {
661 props->setBoolValue("/sim/startup/intro-music", true);
662 } else if ( arg == "--disable-mouse-pointer" ) {
663 props->setStringValue("/sim/startup/mouse-pointer", "disabled");
664 } else if ( arg == "--enable-mouse-pointer" ) {
665 props->setStringValue("/sim/startup/mouse-pointer", "enabled");
666 } else if ( arg == "--disable-freeze" ) {
667 props->setBoolValue("/sim/freeze", false);
668 } else if ( arg == "--enable-freeze" ) {
669 props->setBoolValue("/sim/freeze", true);
670 } else if ( arg == "--disable-anti-alias-hud" ) {
671 props->setBoolValue("/sim/hud/antialiased", false);
672 } else if ( arg == "--enable-anti-alias-hud" ) {
673 props->setBoolValue("/sim/hud/antialiased", true);
674 } else if ( arg.find( "--control=") != string::npos ) {
675 props->setStringValue("/sim/control-mode", arg.substr(10));
676 } else if ( arg == "--disable-auto-coordination" ) {
677 props->setBoolValue("/sim/auto-coordination", false);
678 } else if ( arg == "--enable-auto-coordination" ) {
679 props->setBoolValue("/sim/auto-coordination", true);
680 } else if ( arg == "--disable-hud" ) {
681 props->setBoolValue("/sim/hud/visibility", false);
682 } else if ( arg == "--enable-hud" ) {
683 props->setBoolValue("/sim/hud/visibility", true);
684 } else if ( arg == "--disable-panel" ) {
685 props->setBoolValue("/sim/panel/visibility", false);
686 } else if ( arg == "--enable-panel" ) {
687 props->setBoolValue("/sim/panel/visibility", true);
688 } else if ( arg == "--disable-sound" ) {
689 props->setBoolValue("/sim/sound", false);
690 } else if ( arg == "--enable-sound" ) {
691 props->setBoolValue("/sim/sound", true);
692 } else if ( arg.find( "--airport-id=") != string::npos ) {
693 // NB: changed property name!!!
694 props->setStringValue("/sim/startup/airport-id", arg.substr(13));
695 } else if ( arg.find( "--lon=" ) != string::npos ) {
696 props->setDoubleValue("/position/longitude",
697 parse_degree(arg.substr(6)));
698 props->setStringValue("/position/airport-id", "");
699 } else if ( arg.find( "--lat=" ) != string::npos ) {
700 props->setDoubleValue("/position/latitude",
701 parse_degree(arg.substr(6)));
702 props->setStringValue("/position/airport-id", "");
703 } else if ( arg.find( "--altitude=" ) != string::npos ) {
704 if ( props->getStringValue("/sim/startup/units") == "feet" )
705 props->setDoubleValue(atof(arg.substr(11)));
707 props->setDoubleValue(atof(arg.substr(11)) * METER_TO_FEET);
708 } else if ( arg.find( "--uBody=" ) != string::npos ) {
709 props->setStringValue("/sim/startup/speed-set", "UVW");
710 // FIXME: the units are totally confused here
711 if ( props->getStringValue("/sim/startup/units") == "feet" )
712 props->setDoubleValue("/velocities/uBody", atof(arg.substr(8)));
714 props->setDoubleValue("/velocities/uBody",
715 atof(arg.substr(8)) * FEET_TO_METER);
716 } else if ( arg.find( "--vBody=" ) != string::npos ) {
717 props->setStringValue("/sim/startup/speed-set", "UVW");
718 // FIXME: the units are totally confused here
719 if ( props->getStringValue("/sim/startup/units") == "feet" )
720 props->setDoubleValue("/velocities/vBody", atof(arg.substr(8)));
722 props->setDoubleValue("/velocities/vBody",
723 atof(arg.substr(8)) * FEET_TO_METER);
724 } else if ( arg.find( "--wBody=" ) != string::npos ) {
725 props->setStringValue("/sim/startup/speed-set", "UVW");
726 // FIXME: the units are totally confused here
727 if ( props->getStringValue("/sim/startup/units") == "feet" )
728 props->setDoubleValue("/velocities/wBody", atof(arg.substr(8)));
730 props->setDoubleValue("/velocities/wBody",
731 atof(arg.substr(8)) * FEET_TO_METER);
732 } else if ( arg.find( "--vNorth=" ) != string::npos ) {
733 props->setStringValue("/sim/startup/speed-set", "NED");
734 // FIXME: the units are totally confused here
735 if ( props->getStringValue("/sim/startup/units") == "feet" )
736 props->setDoubleValue("/velocities/speed-north", atof(arg.substr(8)));
738 props->setDoubleValue("/velocities/speed-north",
739 atof(arg.substr(8)) * FEET_TO_METER);
740 } else if ( arg.find( "--vEast=" ) != string::npos ) {
741 props->setStringValue("/sim/startup/speed-set", "NED");
742 // FIXME: the units are totally confused here
743 if ( props->getStringValue("/sim/startup/units") == "feet" )
744 props->setDoubleValue("/velocities/speed-east", atof(arg.substr(8)));
746 props->setDoubleValue("/velocities/speed-east",
747 atof(arg.substr(8)) * FEET_TO_METER);
748 } else if ( arg.find( "--vDown=" ) != string::npos ) {
749 props->setStringValue("/sim/startup/speed-set", "NED");
750 // FIXME: the units are totally confused here
751 if ( props->getStringValue("/sim/startup/units") == "feet" )
752 props->setDoubleValue("/velocities/speed-down", atof(arg.substr(8)));
754 props->setDoubleValue("/velocities/speed-down",
755 atof(arg.substr(8)) * FEET_TO_METER);
756 } else if ( arg.find( "--vc=" ) != string::npos) {
757 props->setStringValue("/sim/startup/speed-set", "knots");
758 props->setDoubleValue("/velocities/airspeed", atof(arg.substr(5)));
759 } else if ( arg.find( "--mach=" ) != string::npos) {
760 props->setStringValue("/sim/startup/speed-set", "mach");
761 props->setDoubleValue("/velocities/mach", atof(arg.substr(7)));
762 } else if ( arg.find( "--heading=" ) != string::npos ) {
763 props->setDoubleValue("/orientation/heading", atof(arg.substr(10)));
764 } else if ( arg.find( "--roll=" ) != string::npos ) {
765 props->setDoubleValue("/orientation/roll", atof(arg.substr(7)));
766 } else if ( arg.find( "--pitch=" ) != string::npos ) {
767 props->setDoubleValue("/orientation/pitch", atof(arg.substr(8)));
768 } else if ( arg.find( "--fg-root=" ) != string::npos ) {
769 globals->set_fg_root(arg.substr( 10 ));
770 } else if ( arg.find( "--fg-scenery=" ) != string::npos ) {
771 globals->set_fg_scenery(arg.substr( 13 ));
772 } else if ( arg.find( "--fdm=" ) != string::npos ) {
773 props->setStringValue("/sim/flight-model", arg.substr(6));
774 // FIXME: reimplement this logic, somehow
775 // if((flight_model == FGInterface::FG_JSBSIM) && (get_trim_mode() == 0)) {
781 } else if ( arg.find( "--aircraft=" ) != string::npos ) {
782 props->setStringValue("/sim/aircraft", arg.substr(11));
783 } else if ( arg.find( "--aircraft-dir=" ) != string::npos ) {
784 props->setStringValue("/sim/aircraft-dir", arg.substr(15));
785 } else if ( arg.find( "--model-hz=" ) != string::npos ) {
786 props->setIntValue("/sim/model-hz", atoi(arg.substr(11)));
787 } else if ( arg.find( "--speed=" ) != string::npos ) {
788 props->setIntValue("/sim/speed-up", atoi(arg.substr(8)));
789 } else if ( arg.find( "--notrim") != string::npos) {
790 props->setIntValue("/sim/startup/trim", -1);
791 } else if ( arg == "--fog-disable" ) {
792 props->setStringValue("/sim/rendering/fog", "disabled");
793 } else if ( arg == "--fog-fastest" ) {
794 props->setStringValue("/sim/rendering/fog", "fastest");
795 } else if ( arg == "--fog-nicest" ) {
796 props->setStringValue("/sim/fog", "nicest");
797 } else if ( arg == "--disable-clouds" ) {
798 props->setBoolValue("/environment/clouds/enabled", false);
799 } else if ( arg == "--enable-clouds" ) {
800 props->setBoolValue("/environment/clouds/enabled", true);
801 } else if ( arg.find( "--clouds-asl=" ) != string::npos ) {
802 // FIXME: check units
803 if ( props->getStringValue("/sim/startup/units") == "feet" )
804 props->setDoubleValue("/environment/clouds/altitude",
805 atof(arg.substr(13)) * FEET_TO_METER);
807 props->setDoubleValue("/environment/clouds/altitude",
808 atof(arg.substr(13)));
809 } else if ( arg.find( "--fov=" ) != string::npos ) {
810 parse_fov( arg.substr(6) );
811 } else if ( arg == "--disable-fullscreen" ) {
812 props->setBoolValue("/sim/startup/fullscreen", false);
813 } else if ( arg== "--enable-fullscreen") {
814 props->setBoolValue("/sim/startup/fullscreen", true);
815 } else if ( arg == "--shading-flat") {
816 props->setBoolValue("/sim/rendering/shading", false);
817 } else if ( arg == "--shading-smooth") {
818 props->setBoolValue("/sim/rendering/shading", true);
819 } else if ( arg == "--disable-skyblend") {
820 props->setBoolValue("/sim/rendering/skyblend", false);
821 } else if ( arg== "--enable-skyblend" ) {
822 props->setBoolValue("/sim/rendering/skyblend", true);
823 } else if ( arg == "--disable-textures" ) {
824 props->setBoolValue("/sim/rendering/textures", false);
825 } else if ( arg == "--enable-textures" ) {
826 props->setBoolValue("/sim/rendering/textures", true);
827 } else if ( arg == "--disable-wireframe" ) {
828 props->setBoolValue("/sim/rendering/wireframe", false);
829 } else if ( arg == "--enable-wireframe" ) {
830 props->setBoolValue("/sim/rendering/wireframe", true);
831 } else if ( arg.find( "--geometry=" ) != string::npos ) {
832 bool geometry_ok = true;
833 int xsize = 0, ysize = 0;
834 string geometry = arg.substr( 11 );
835 string::size_type i = geometry.find('x');
837 if (i != string::npos) {
838 xsize = atoi(geometry.substr(0, i));
839 ysize = atoi(geometry.substr(i+1));
844 if ( xsize <= 0 || ysize <= 0 ) {
850 if ( !geometry_ok ) {
851 FG_LOG( FG_GENERAL, FG_ALERT, "Unknown geometry: " << geometry );
852 FG_LOG( FG_GENERAL, FG_ALERT,
853 "Setting geometry to " << xsize << 'x' << ysize << '\n');
855 FG_LOG( FG_GENERAL, FG_INFO,
856 "Setting geometry to " << xsize << 'x' << ysize << '\n');
857 props->setIntValue("/sim/startup/xsize", xsize);
858 props->setIntValue("/sim/startup/ysize", ysize);
860 } else if ( arg.find( "--bpp=" ) != string::npos ) {
861 string bits_per_pix = arg.substr( 6 );
862 if ( bits_per_pix == "16" ) {
863 props->setIntValue("/sim/rendering/bits-per-pixel", 16);
864 } else if ( bits_per_pix == "24" ) {
865 props->setIntValue("/sim/rendering/bits-per-pixel", 24);
866 } else if ( bits_per_pix == "32" ) {
867 props->setIntValue("/sim/rendering/bits-per-pixel", 32);
869 FG_LOG(FG_GENERAL, FG_ALERT, "Unsupported bpp " << bits_per_pix);
871 } else if ( arg == "--units-feet" ) {
872 props->setStringValue("/sim/startup/units", "feet");
873 } else if ( arg == "--units-meters" ) {
874 props->setStringValue("/sim/startup/units", "meters");
875 } else if ( arg.find( "--time-offset" ) != string::npos ) {
876 props->setIntValue("/sim/startup/time-offset",
877 parse_time_offset( (arg.substr(14)) ));
878 } else if ( arg.find( "--time-match-real") != string::npos ) {
879 props->setStringValue("/sim/startup/time-offset_type",
881 } else if ( arg.find( "--time-match-local") != string::npos ) {
882 props->setStringValue("/sim/startup/time-offset_type",
884 } else if ( arg.find( "--start-date-sys=") != string::npos ) {
885 props->setIntValue("/sim/startup/time-offset",
886 parse_date((arg.substr(17))));
887 props->setStringValue("/sim/startup/time-offset-type", "system");
888 } else if ( arg.find( "--start-date-lat=") != string::npos ) {
889 props->setIntValue("/sim/startup/time-offset",
890 parse_date((arg.substr(17))));
891 props->setStringValue("/sim/startup/time-offset-type",
893 } else if ( arg.find( "--start-date-gmt=") != string::npos ) {
894 props->setIntValue("/sim/startup/time-offset",
895 parse_date((arg.substr(17))));
896 props->setStringValue("/sim/startup/time-offset-type", "gmt");
897 } else if ( arg == "--hud-tris" ) {
898 props->setStringValue("/sim/hud/frame-stat-type", "tris");
899 } else if ( arg == "--hud-culled" ) {
900 props->setStringValue("/sim/hud/frame-stat-type", "culled");
901 } else if ( arg.find( "--native=" ) != string::npos ) {
902 parse_channel( "native", arg.substr(9) );
903 } else if ( arg.find( "--garmin=" ) != string::npos ) {
904 parse_channel( "garmin", arg.substr(9) );
905 } else if ( arg.find( "--nmea=" ) != string::npos ) {
906 parse_channel( "nmea", arg.substr(7) );
907 } else if ( arg.find( "--props=" ) != string::npos ) {
908 parse_channel( "props", arg.substr(8) );
909 } else if ( arg.find( "--pve=" ) != string::npos ) {
910 parse_channel( "pve", arg.substr(6) );
911 } else if ( arg.find( "--ray=" ) != string::npos ) {
912 parse_channel( "ray", arg.substr(6) );
913 } else if ( arg.find( "--rul=" ) != string::npos ) {
914 parse_channel( "rul", arg.substr(6) );
915 } else if ( arg.find( "--joyclient=" ) != string::npos ) {
916 parse_channel( "joyclient", arg.substr(12) );
917 #ifdef FG_NETWORK_OLK
918 } else if ( arg == "--disable-network-olk" ) {
919 props->setBoolValue("/sim/networking/olk", false);
920 } else if ( arg== "--enable-network-olk") {
921 props->setBoolValue("/sim/networking/olk", true);
922 } else if ( arg == "--net-hud" ) {
923 props->setBoolValue("/sim/hud/net-display", true);
924 net_hud_display = 1; // FIXME
925 } else if ( arg.find( "--net-id=") != string::npos ) {
926 props->setStringValue("sim/networking/call-sign", arg.substr(9));
928 } else if ( arg.find( "--prop:" ) == 0 ) {
929 string assign = arg.substr(7);
930 int pos = assign.find('=');
931 if (pos == arg.npos || pos == 0) {
932 FG_LOG(FG_GENERAL, FG_ALERT, "Bad property assignment: " << arg);
933 return FG_OPTIONS_ERROR;
935 string name = assign.substr(0, pos);
936 string value = assign.substr(pos + 1);
937 props->setStringValue(name.c_str(), value);
938 FG_LOG(FG_GENERAL, FG_INFO, "Setting default value of property "
939 << name << " to \"" << value << '"');
940 // $$$ begin - added VS Renganathan, 14 Oct 2K
941 // for multi-window outside window imagery
942 } else if ( arg.find( "--view-offset=" ) != string::npos ) {
943 string woffset = arg.substr( 14 );
944 double default_view_offset = 0.0;
945 if ( woffset == "LEFT" ) {
946 default_view_offset = FG_PI * 0.25;
947 } else if ( woffset == "RIGHT" ) {
948 default_view_offset = FG_PI * 1.75;
949 } else if ( woffset == "CENTER" ) {
950 default_view_offset = 0.00;
952 default_view_offset = atof( woffset.c_str() ) * DEG_TO_RAD;
954 FGViewerRPH *pilot_view =
955 (FGViewerRPH *)globals->get_viewmgr()->get_view( 0 );
956 pilot_view->set_view_offset( default_view_offset );
957 pilot_view->set_goal_view_offset( default_view_offset );
958 props->setDoubleValue("/sim/startup/view-offset", default_view_offset);
959 // $$$ end - added VS Renganathan, 14 Oct 2K
960 } else if ( arg.find( "--visibility=" ) != string::npos ) {
961 props->setDoubleValue("/environment/visibility", atof(arg.substr(13)));
962 } else if ( arg.find( "--visibility-miles=" ) != string::npos ) {
963 double visibility = atof(arg.substr(19)) * 5280.0 * FEET_TO_METER;
964 props->setDoubleValue("/environment/visibility", visibility);
965 } else if ( arg.find( "--wind=" ) == 0 ) {
966 string val = arg.substr(7);
967 int pos = val.find('@');
968 if (pos == string::npos) {
969 FG_LOG(FG_GENERAL, FG_ALERT, "bad wind value " << val);
970 return FG_OPTIONS_ERROR;
972 double dir = atof(val.substr(0,pos).c_str());
973 double speed = atof(val.substr(pos+1).c_str());
974 FG_LOG(FG_GENERAL, FG_INFO, "WIND: " << dir << '@' <<
975 speed << " knots" << endl);
977 speed *= NM_TO_METER * METER_TO_FEET * (1.0/3600);
982 props->setDoubleValue("/environment/wind-north",
984 props->setDoubleValue("/environment/wind-east",
986 } else if ( arg.find( "--wp=" ) != string::npos ) {
987 parse_wp( arg.substr( 5 ) );
988 } else if ( arg.find( "--flight-plan=") != string::npos) {
989 parse_flightplan ( arg.substr (14) );
991 FG_LOG( FG_GENERAL, FG_ALERT, "Unknown option '" << arg << "'" );
992 return FG_OPTIONS_ERROR;
995 return FG_OPTIONS_OK;
999 // Scan the command line options for an fg_root definition and set
1001 int FGOptions::scan_command_line_for_root( int argc, char **argv ) {
1004 FG_LOG(FG_GENERAL, FG_INFO, "Processing command line arguments");
1006 while ( i < argc ) {
1007 FG_LOG( FG_GENERAL, FG_DEBUG, "argv[" << i << "] = " << argv[i] );
1009 string arg = argv[i];
1010 if ( arg.find( "--fg-root=" ) != string::npos ) {
1011 globals->set_fg_root(arg.substr( 10 ));
1017 return FG_OPTIONS_OK;
1021 // Scan the config file for an fg_root definition and set just that.
1022 int FGOptions::scan_config_file_for_root( const string& path ) {
1023 fg_gzifstream in( path );
1024 if ( !in.is_open() )
1025 return(FG_OPTIONS_ERROR);
1027 FG_LOG( FG_GENERAL, FG_INFO, "Scanning for root: " << path );
1031 while ( ! in.eof() ) {
1034 while ( in.get(c) && c != '\0' ) {
1039 #ifdef GETLINE_NEEDS_TERMINATOR
1040 getline( in, line, '\n' );
1041 #elif defined( macintosh )
1042 getline( in, line, '\r' );
1044 getline( in, line );
1047 if ( line.find( "--fg-root=" ) != string::npos ) {
1048 globals->set_fg_root(line.substr( 10 ));
1054 return FG_OPTIONS_OK;
1058 // Parse the command line options
1059 int FGOptions::parse_command_line( int argc, char **argv ) {
1063 FG_LOG(FG_GENERAL, FG_INFO, "Processing command line arguments");
1065 while ( i < argc ) {
1066 FG_LOG( FG_GENERAL, FG_DEBUG, "argv[" << i << "] = " << argv[i] );
1068 result = parse_option(argv[i]);
1069 if ( (result == FG_OPTIONS_HELP) || (result == FG_OPTIONS_ERROR) ) {
1076 return FG_OPTIONS_OK;
1080 // Parse config file options
1081 int FGOptions::parse_config_file( const string& path ) {
1082 fg_gzifstream in( path );
1083 if ( !in.is_open() )
1084 return(FG_OPTIONS_ERROR);
1086 FG_LOG( FG_GENERAL, FG_INFO, "Processing config file: " << path );
1090 while ( ! in.eof() ) {
1093 while ( in.get(c) && c != '\0' ) {
1098 #ifdef GETLINE_NEEDS_TERMINATOR
1099 getline( in, line, '\n' );
1100 #elif defined( macintosh )
1101 getline( in, line, '\r' );
1103 getline( in, line );
1106 if ( parse_option( line ) == FG_OPTIONS_ERROR ) {
1107 FG_LOG( FG_GENERAL, FG_ALERT,
1108 "Config file parse error: " << path << " '"
1115 return FG_OPTIONS_OK;
1119 // Print usage message
1120 void FGOptions::usage ( void ) {
1121 cout << "Usage: fg [ options ... ]" << endl;
1124 cout << "General Options:" << endl;
1125 cout << "\t--help -h: print usage" << endl;
1126 cout << "\t--fg-root=path: specify the root path for all the data files"
1128 cout << "\t--fg-scenery=path: specify the base path for all the scenery"
1130 << "\t\tdefaults to $FG_ROOT/Scenery" << endl;
1131 cout << "\t--disable-game-mode: disable full-screen game mode" << endl;
1132 cout << "\t--enable-game-mode: enable full-screen game mode" << endl;
1133 cout << "\t--disable-splash-screen: disable splash screen" << endl;
1134 cout << "\t--enable-splash-screen: enable splash screen" << endl;
1135 cout << "\t--disable-intro-music: disable introduction music" << endl;
1136 cout << "\t--enable-intro-music: enable introduction music" << endl;
1137 cout << "\t--disable-mouse-pointer: disable extra mouse pointer" << endl;
1138 cout << "\t--enable-mouse-pointer: enable extra mouse pointer (i.e. for"
1140 cout << "\t\tfull screen voodoo/voodoo-II based cards.)" << endl;
1141 cout << "\t--disable-freeze: start out in an running state" << endl;
1142 cout << "\t--enable-freeze: start out in a frozen state" << endl;
1143 cout << "\t--control=mode: primary control mode "
1144 << "(joystick, keyboard, mouse)" << endl;
1147 cout << "Features:" << endl;
1148 cout << "\t--disable-hud: disable heads up display" << endl;
1149 cout << "\t--enable-hud: enable heads up display" << endl;
1150 cout << "\t--disable-panel: disable instrument panel" << endl;
1151 cout << "\t--enable-panel: enable instrumetn panel" << endl;
1152 cout << "\t--disable-sound: disable sound effects" << endl;
1153 cout << "\t--enable-sound: enable sound effects" << endl;
1154 cout << "\t--disable-anti-alias-hud: disable anti aliased hud" << endl;
1155 cout << "\t--enable-anti-alias-hud: enable anti aliased hud" << endl;
1158 cout << "Flight Model:" << endl;
1159 cout << "\t--fdm=abcd: selects the core flight model code." << endl;
1160 cout << "\t\tcan be one of jsb, larcsim, magic, external, balloon, or ada"
1162 cout << "\t--aircraft=abcd: aircraft model to load" << endl;
1163 cout << "\t--model-hz=n: run the FDM this rate (iterations per second)"
1165 cout << "\t--speed=n: run the FDM this much faster than real time" << endl;
1166 cout << "\t--notrim: Do NOT attempt to trim the model when initializing JSBsim" << endl;
1167 cout << "\t--wind=DIR@SPEED: specify wind coming from DIR (degrees) at SPEED (knots)" << endl;
1171 cout <<"Aircraft model directory:" << endl;
1172 cout <<"\t--aircraft-dir=<path> path is relative to the path of the executable" << endl;
1175 cout << "Initial Position and Orientation:" << endl;
1176 cout << "\t--airport-id=ABCD: specify starting postion by airport id"
1178 cout << "\t--lon=degrees: starting longitude in degrees (west = -)"
1180 cout << "\t--lat=degrees: starting latitude in degrees (south = -)"
1182 cout << "\t--altitude=feet: starting altitude in feet" << endl;
1183 cout << "\t\t(unless --units-meters specified" << endl;
1184 cout << "\t--heading=degrees: heading (yaw) angle in degress (Psi)"
1186 cout << "\t--roll=degrees: roll angle in degrees (Phi)" << endl;
1187 cout << "\t--pitch=degrees: pitch angle in degrees (Theta)" << endl;
1188 cout << "\t--uBody=feet per second: velocity along the body X axis"
1190 cout << "\t--vBody=feet per second: velocity along the body Y axis"
1192 cout << "\t--wBody=feet per second: velocity along the body Z axis"
1194 cout << "\t\t(unless --units-meters specified" << endl;
1195 cout << "\t--vc= initial airspeed in knots (--fdm=jsb only)" << endl;
1196 cout << "\t--mach= initial mach number (--fdm=jsb only)" << endl;
1199 cout << "Rendering Options:" << endl;
1200 cout << "\t--fog-disable: disable fog/haze" << endl;
1201 cout << "\t--fog-fastest: enable fastest fog/haze" << endl;
1202 cout << "\t--fog-nicest: enable nicest fog/haze" << endl;
1203 cout << "\t--enable-clouds: enable demo cloud layer" << endl;
1204 cout << "\t--disable-clouds: disable demo cloud layer" << endl;
1205 cout << "\t--clouds-asl=xxx: specify altitude of cloud layer above sea level" << endl;
1206 cout << "\t--fov=xx.x: specify initial field of view angle in degrees"
1208 cout << "\t--disable-fullscreen: disable fullscreen mode" << endl;
1209 cout << "\t--enable-fullscreen: enable fullscreen mode" << endl;
1210 cout << "\t--shading-flat: enable flat shading" << endl;
1211 cout << "\t--shading-smooth: enable smooth shading" << endl;
1212 cout << "\t--disable-skyblend: disable sky blending" << endl;
1213 cout << "\t--enable-skyblend: enable sky blending" << endl;
1214 cout << "\t--disable-textures: disable textures" << endl;
1215 cout << "\t--enable-textures: enable textures" << endl;
1216 cout << "\t--disable-wireframe: disable wireframe drawing mode" << endl;
1217 cout << "\t--enable-wireframe: enable wireframe drawing mode" << endl;
1218 cout << "\t--geometry=WWWxHHH: window geometry: 640x480, 800x600, etc."
1220 cout << "\t--view-offset=xxx: set the default forward view direction"
1222 cout << "\t\tas an offset from straight ahead. Allowable values are"
1224 cout << "\t\tLEFT, RIGHT, CENTER, or a specific number of degrees" << endl;
1225 cout << "\t--visibility=xxx: specify initial visibility in meters" << endl;
1226 cout << "\t--visibility-miles=xxx: specify initial visibility in miles"
1230 cout << "Scenery Options:" << endl;
1231 cout << "\t--tile-radius=n: specify tile radius, must be 1 - 4" << endl;
1234 cout << "Hud Options:" << endl;
1235 cout << "\t--units-feet: Hud displays units in feet" << endl;
1236 cout << "\t--units-meters: Hud displays units in meters" << endl;
1237 cout << "\t--hud-tris: Hud displays number of triangles rendered" << endl;
1238 cout << "\t--hud-culled: Hud displays percentage of triangles culled"
1242 cout << "Time Options:" << endl;
1243 cout << "\t--time-offset=[+-]hh:mm:ss: add this time offset" << endl;
1244 cout << "\t--time-match-real: Synchronize real-world and FlightGear" << endl
1245 << "\t\ttime. Can be used in combination with --time-offset." << endl;
1246 cout << "\t--time-match-local:Synchronize local real-world and " << endl
1247 << "\t\tFlightGear time" << endl;
1248 cout << "\t--start-date-sys=yyyy:mm:dd:hh:mm:ss: specify a starting" << endl
1249 << "\t\tdate/time. Uses your system time " << endl;
1250 cout << "\t--start-date-gmt=yyyy:mm:dd:hh:mm:ss: specify a starting" << endl
1251 << "\t\tdate/time. Uses Greenwich Mean Time" << endl;
1252 cout << "\t--start-date-lat=yyyy:mm:dd:hh:mm:ss: specify a starting" << endl
1253 << "\t\tdate/time. Uses Local Aircraft Time" << endl;
1254 #ifdef FG_NETWORK_OLK
1257 cout << "Network Options:" << endl;
1258 cout << "\t--enable-network-olk: enable Multipilot mode" << endl;
1259 cout << "\t--disable-network-olk: disable Multipilot mode (default)" << endl;
1260 cout << "\t--net-hud: Hud displays network info" << endl;
1261 cout << "\t--net-id=name: specify your own callsign" << endl;
1265 cout << "Route/Way Point Options:" << endl;
1266 cout << "\t--wp=ID[@alt]: specify a waypoint for the GC autopilot" << endl;
1267 cout << "\t\tYou can specify multiple waypoints (a route) with multiple"
1269 cout << "\t\tinstances of --wp=" << endl;
1270 cout << "\t--flight-plan=[file]: Read all waypoints from [file]" <<endl;
1275 FGOptions::~FGOptions( void ) {
1280 // Temporary methods...
1284 FGOptions::get_fg_root() const
1286 return globals->get_fg_root();
1290 FGOptions::get_fg_scenery () const
1292 return globals->get_fg_scenery();
1296 FGOptions::get_channel_options_list () const
1298 return globals->get_channel_options_list();