FlightGear next
fg_scene_commands.cxx
Go to the documentation of this file.
1/*
2 * SPDX-FileName: fg_scene_commands.cxx
3 * SPDX-FileComment: internal FGFS commands
4 */
5
6#include "config.h"
7
8#include <string.h> // strcmp()
9
10#include <simgear/compiler.h>
11
12#include <string>
13#include <fstream>
14
15#include <simgear/sg_inlines.h>
16#include <simgear/debug/logstream.hxx>
17#include <simgear/math/sg_random.hxx>
18#include <simgear/io/iostreams/sgstream.hxx>
19#include <simgear/scene/material/mat.hxx>
20#include <simgear/scene/material/matlib.hxx>
21#include <simgear/structure/exception.hxx>
22#include <simgear/structure/commands.hxx>
23#include <simgear/props/props.hxx>
24#include <simgear/props/props_io.hxx>
25#include <simgear/structure/event_mgr.hxx>
26#include <simgear/sound/soundmgr.hxx>
27#include <simgear/timing/sg_time.hxx>
29
30#include <FDM/flight.hxx>
31#include <GUI/gui.h>
32#include <GUI/new_gui.hxx>
33#include <GUI/dialog.hxx>
34#include <Aircraft/replay.hxx>
35#include <Scenery/scenery.hxx>
41#include <Viewer/viewmgr.hxx>
42#include <Viewer/view.hxx>
45
46#include "fg_init.hxx"
47#include "fg_io.hxx"
48#include "fg_os.hxx"
49#include "fg_commands.hxx"
50#include "fg_props.hxx"
51#include "globals.hxx"
52#include "logger.hxx"
53#include "util.hxx"
54#include "main.hxx"
55#include "positioninit.hxx"
56
57#if FG_HAVE_GPERFTOOLS
58# include <google/profiler.h>
59#endif
60
61#if defined(HAVE_QT)
62#include <GUI/QtLauncher.hxx>
63#endif
64
65
67// Command implementations.
69
75static bool
76do_exit (const SGPropertyNode * arg, SGPropertyNode * root)
77{
78 SG_LOG(SG_INPUT, SG_INFO, "Program exit requested.");
79 fgSetBool("/sim/signals/exit", true);
80 globals->saveUserSettings();
81 fgOSExit(arg->getIntValue("status", 0));
82 return true;
83}
84
85
89static bool
90do_reset (const SGPropertyNode * arg, SGPropertyNode * root)
91{
93 return true;
94}
95
96
100static bool
101do_switch_aircraft (const SGPropertyNode * arg, SGPropertyNode * root)
102{
103 fgSetString("/sim/aircraft", arg->getStringValue("aircraft"));
104
105 // we could validate the new aircraft is find-able, and if not, bail out
106 // of the command at this point? Might give a better user experience?
107 // would need something like bool fgIsValidAircraft(name, dir);
108 // which could be cooked up by modifying FindAndCacheAircraft
109
110 // We assume that we are changing the aircraft, so we remove the aircraft path.
111 // this forces aircraft-dir to be recomputed by a full search as the user hopefully
112 // expects.
113 // We could allow pasing the dir as an optional argument to this command, if that
114 // is ever needed in the future.
115 fgGetNode("/sim")->removeChild("aircraft-dir");
116
117 // start a reset
119 return true;
120}
121
124static bool
125do_reposition (const SGPropertyNode * arg, SGPropertyNode * root)
126{
128 return true;
129}
130
138static bool
139do_panel_load (const SGPropertyNode * arg, SGPropertyNode * root)
140{
141 std::string panel_path = arg->getStringValue("path");
142 if (!panel_path.empty()) {
143 // write to the standard property, which will force a load
144 fgSetString("/sim/panel/path", panel_path.c_str());
145 }
146
147 return true;
148}
149
156static bool
157do_preferences_load (const SGPropertyNode * arg, SGPropertyNode * root)
158{
159 // disabling this command which was formerly used to reload 'preferences.xml'
160 // reloading the defaults doesn't make sense (better to reset the simulator),
161 // and loading arbitrary XML docs into the property-tree can be done via
162 // the standard load-xml command.
163 SG_LOG(SG_GENERAL, SG_ALERT, "preferences-load command is deprecated and non-functional");
164 return false;
165}
166
171static bool
172do_toggle_fullscreen(const SGPropertyNode*, SGPropertyNode*)
173{
175 return true;
176}
177
181static bool
182do_screen_capture(const SGPropertyNode*, SGPropertyNode*)
183{
184 return fgDumpSnapShot();
185}
186
187static bool
188do_reload_shaders (const SGPropertyNode*, SGPropertyNode*)
189{
190 simgear::reload_shaders();
191 return true;
192}
193
194static bool
195do_dump_scene_graph (const SGPropertyNode*, SGPropertyNode*)
196{
198 return true;
199}
200
201static bool
202do_dump_terrain_branch (const SGPropertyNode*, SGPropertyNode*)
203{
205
206 double lon_deg = fgGetDouble("/position/longitude-deg");
207 double lat_deg = fgGetDouble("/position/latitude-deg");
208 SGGeod geodPos = SGGeod::fromDegFt(lon_deg, lat_deg, 0.0);
209 SGVec3d zero = SGVec3d::fromGeod(geodPos);
210
211 SG_LOG(SG_INPUT, SG_INFO, "Model parameters:");
212 SG_LOG(SG_INPUT, SG_INFO, "Center: " << zero.x() << ", " << zero.y() << ", " << zero.z() );
213 SG_LOG(SG_INPUT, SG_INFO, "Rotation: " << lat_deg << ", " << lon_deg );
214
215 return true;
216}
217
218static bool
219do_print_visible_scene_info(const SGPropertyNode*, SGPropertyNode*)
220{
222 return true;
223}
224
228static bool
229do_reload_compositor(const SGPropertyNode*, SGPropertyNode*)
230{
232 return true;
233}
234
238static bool
239do_tile_cache_reload (const SGPropertyNode * arg, SGPropertyNode * root)
240{
241 SGPropertyNode *master_freeze = fgGetNode("/sim/freeze/master");
242 bool freeze = master_freeze->getBoolValue();
243 SG_LOG(SG_INPUT, SG_INFO, "ReIniting TileCache");
244 if ( !freeze ) {
245 master_freeze->setBoolValue(true);
246 }
247
248 globals->get_subsystem<FGScenery>()->reinit();
249
250 if ( !freeze ) {
251 master_freeze->setBoolValue(false);
252 }
253 return true;
254}
255
259static bool
260do_materials_reload (const SGPropertyNode * arg, SGPropertyNode * root)
261{
262 SG_LOG(SG_INPUT, SG_INFO, "Reloading Materials");
263 SGMaterialLib* new_matlib = new SGMaterialLib;
264 SGPath mpath( globals->get_fg_root() );
265 mpath.append( fgGetString("/sim/rendering/materials-file") );
266 bool loaded = new_matlib->load(globals->get_fg_root(),
267 mpath,
268 globals->get_props());
269
270 if ( ! loaded ) {
271 SG_LOG( SG_GENERAL, SG_ALERT,
272 "Error loading materials file " << mpath );
273 return false;
274 }
275
276 globals->set_matlib(new_matlib);
277 FGScenery* scenery = static_cast<FGScenery*>(globals->get_scenery());
278 scenery->materialLibChanged();
279
280 return true;
281}
282
290static bool
291do_dialog_new (const SGPropertyNode * arg, SGPropertyNode * root)
292{
293 auto gui = globals->get_subsystem<NewGUI>();
294 if (!gui) {
295 return false;
296 }
297
298 // Note the casting away of const: this is *real*. Doing a
299 // "dialog-apply" command later on will mutate this property node.
300 // I'm not convinced that this isn't the Right Thing though; it
301 // allows client to create a node, pass it to dialog-new, and get
302 // the values back from the dialog by reading the same node.
303 // Perhaps command arguments are not as "const" as they would
304 // seem?
305 gui->newDialog((SGPropertyNode*)arg);
306 return true;
307}
308
314static bool
315do_dialog_show (const SGPropertyNode * arg, SGPropertyNode * root)
316{
317 auto gui = globals->get_subsystem<NewGUI>();
318 gui->showDialog(arg->getStringValue("dialog-name"));
319 return true;
320}
321
327static bool
328do_dialog_toggle (const SGPropertyNode * arg, SGPropertyNode * root)
329{
330 auto gui = globals->get_subsystem<NewGUI>();
331 gui->toggleDialog(arg->getStringValue("dialog-name"));
332 return true;
333}
334
335
339static bool
340do_dialog_close (const SGPropertyNode * arg, SGPropertyNode * root)
341{
342 auto gui = globals->get_subsystem<NewGUI>();
343 if(arg->hasValue("dialog-name"))
344 return gui->closeDialog(arg->getStringValue("dialog-name"));
345 return gui->closeActiveDialog();
346}
347
348
354static bool
355do_dialog_update (const SGPropertyNode * arg, SGPropertyNode * root)
356{
357 auto gui = globals->get_subsystem<NewGUI>();
358 FGDialog * dialog;
359 if (arg->hasValue("dialog-name"))
360 dialog = gui->getDialog(arg->getStringValue("dialog-name"));
361 else
362 dialog = gui->getActiveDialog();
363
364 if (dialog != 0) {
365 dialog->updateValues(arg->getStringValue("object-name"));
366 return true;
367 } else {
368 return false;
369 }
370}
371
372static bool
373do_open_browser (const SGPropertyNode * arg, SGPropertyNode * root)
374{
375 std::string path;
376 if (arg->hasValue("path"))
377 path = arg->getStringValue("path");
378 else
379 if (arg->hasValue("url"))
380 path = arg->getStringValue("url");
381 else
382 return false;
383
384 return openBrowser(path);
385}
386
387static bool
388do_open_launcher(const SGPropertyNode*, SGPropertyNode*)
389{
390#if defined(HAVE_QT)
392 if (ok) {
393 // start a full reset
395 }
396 return true; // don't report failure
397#else
398 return false;
399#endif
400}
401
407static bool
408do_dialog_apply (const SGPropertyNode * arg, SGPropertyNode * root)
409{
410 auto gui = globals->get_subsystem<NewGUI>();
411 FGDialog* dialog = nullptr;
412 if (arg->hasValue("dialog-name"))
413 dialog = gui->getDialog(arg->getStringValue("dialog-name"));
414 else
415 dialog = gui->getActiveDialog();
416
417 if (dialog) {
418 dialog->applyValues(arg->getStringValue("object-name"));
419 return true;
420 } else {
421 return false;
422 }
423}
424
425
430static bool
431do_gui_redraw (const SGPropertyNode * arg, SGPropertyNode * root)
432{
433 auto gui = globals->get_subsystem<NewGUI>();
434 gui->redraw();
435 return true;
436}
437
438
443static bool
444do_add_model (const SGPropertyNode * arg, SGPropertyNode * root)
445{
446 SGPropertyNode * model = fgGetNode("models", true);
447 int i;
448 for (i = 0; model->hasChild("model",i); i++);
449 model = model->getChild("model", i, true);
450 copyProperties(arg, model);
451 if (model->hasValue("elevation-m"))
452 model->setDoubleValue("elevation-ft", model->getDoubleValue("elevation-m")
453 * SG_METER_TO_FEET);
454 model->getNode("load", true);
455 model->removeChildren("load");
456 const_cast<SGPropertyNode *>(arg)->setStringValue("property", model->getPath());
457 return true;
458}
459
463static bool
464do_presets_commit (const SGPropertyNode * arg, SGPropertyNode * root)
465{
466 if (fgGetBool("/sim/initialized", false)) {
468 } else {
469 // Nasal can trigger this during initial init, which confuses
470 // the logic in ReInitSubsystems, since initial state has not been
471 // saved at that time. Short-circuit everything here.
473 }
474
475 return true;
476}
477
478static bool
479do_press_cockpit_button (const SGPropertyNode * arg, SGPropertyNode * root)
480{
481 const std::string prefix = arg->getStringValue("prefix");
482
483 if (arg->getBoolValue("guarded") && fgGetDouble((prefix + "-guard").c_str()) < 1)
484 return true;
485
486 std::string prop = prefix + "-button";
487 double value;
488
489 if (arg->getBoolValue("latching"))
490 value = fgGetDouble(prop.c_str()) > 0 ? 0 : 1;
491 else
492 value = 1;
493
494 fgSetDouble(prop.c_str(), value);
495 fgSetBool(arg->getStringValue("discrete"), value > 0);
496
497 return true;
498}
499
500static bool
501do_release_cockpit_button (const SGPropertyNode * arg, SGPropertyNode * root)
502{
503 const std::string prefix = arg->getStringValue("prefix");
504
505 if (arg->getBoolValue("guarded")) {
506 std::string prop = prefix + "-guard";
507 if (fgGetDouble(prop.c_str()) < 1) {
508 fgSetDouble(prop.c_str(), 1);
509 return true;
510 }
511 }
512
513 if (! arg->getBoolValue("latching")) {
514 fgSetDouble((prefix + "-button").c_str(), 0);
515 fgSetBool(arg->getStringValue("discrete"), false);
516 }
517
518 return true;
519}
520
522// Command setup.
524
525
532static struct {
533 const char * name;
534 SGCommandMgr::command_t command;
535} built_ins [] = {
536 { "exit", do_exit },
537 { "reset", do_reset },
538 { "reposition", do_reposition },
539 { "switch-aircraft", do_switch_aircraft },
540 { "panel-load", do_panel_load },
541 { "preferences-load", do_preferences_load },
542 { "toggle-fullscreen", do_toggle_fullscreen },
543 { "screen-capture", do_screen_capture },
544 { "tile-cache-reload", do_tile_cache_reload },
545 { "dialog-new", do_dialog_new },
546 { "dialog-show", do_dialog_show },
547 { "dialog-toggle", do_dialog_toggle },
548 { "dialog-close", do_dialog_close },
549 { "dialog-update", do_dialog_update },
550 { "dialog-apply", do_dialog_apply },
551 { "open-browser", do_open_browser },
552 { "gui-redraw", do_gui_redraw },
553 { "add-model", do_add_model },
554 { "presets-commit", do_presets_commit },
555 { "press-cockpit-button", do_press_cockpit_button },
556 { "release-cockpit-button", do_release_cockpit_button },
557 { "dump-scenegraph", do_dump_scene_graph },
558 { "dump-terrainbranch", do_dump_terrain_branch },
559 { "print-visible-scene", do_print_visible_scene_info },
560 { "reload-shaders", do_reload_shaders },
561 { "reload-materials", do_materials_reload },
562 { "reload-compositor", do_reload_compositor },
563 { "open-launcher", do_open_launcher },
564 { 0, 0 } // zero-terminated
566
567
573void
575{
576 SG_LOG(SG_GENERAL, SG_BULK, "Initializing scene built-in commands:");
577 for (int i = 0; built_ins[i].name != 0; i++) {
578 SG_LOG(SG_GENERAL, SG_BULK, " " << built_ins[i].name);
579 globals->get_commands()->addCommand(built_ins[i].name,
581 }
582
583}
#define i(x)
An XML-configured dialog box.
Definition dialog.hxx:21
void materialLibChanged()
Definition scenery.cxx:553
XML-configured GUI subsystem.
Definition new_gui.hxx:31
virtual bool closeDialog(const std::string &name)
Close a named dialog, if it is open.
Definition new_gui.cxx:369
virtual bool showDialog(const std::string &name)
Display a dialog box.
Definition new_gui.cxx:281
virtual bool toggleDialog(const std::string &name)
Toggle display of a dialog box.
Definition new_gui.cxx:324
virtual void redraw()
Redraw the GUI picking up new GUI colors.
Definition new_gui.cxx:176
virtual void newDialog(SGPropertyNode *node)
Creates a new dialog box, using the same property format as the gui/dialogs configuration files.
Definition new_gui.cxx:479
static CameraGroup * getDefault()
Get the default CameraGroup.
static struct @067026177365276227015073311113211264353134373250 built_ins[]
Table of built-in commands.
SGCommandMgr::command_t command
const char * name
void fgStartReposition()
Definition fg_init.cxx:1204
void fgOSExit(int code)
void fgOSFullScreen()
std::string fgGetString(const char *name, const char *defaultValue)
Get a string value for a property.
Definition fg_props.cxx:556
static bool do_open_launcher(const SGPropertyNode *, SGPropertyNode *)
static bool do_preferences_load(const SGPropertyNode *arg, SGPropertyNode *root)
Built-in command: (re)load preferences.
static bool do_press_cockpit_button(const SGPropertyNode *arg, SGPropertyNode *root)
static bool do_reset(const SGPropertyNode *arg, SGPropertyNode *root)
Reset FlightGear (Shift-Escape or Menu->File->Reset)
static bool do_toggle_fullscreen(const SGPropertyNode *, SGPropertyNode *)
An fgcommand to toggle fullscreen mode.
static bool do_print_visible_scene_info(const SGPropertyNode *, SGPropertyNode *)
void fgInitSceneCommands()
Initialize the default built-in commands.
static bool do_switch_aircraft(const SGPropertyNode *arg, SGPropertyNode *root)
Change aircraft.
static bool do_panel_load(const SGPropertyNode *arg, SGPropertyNode *root)
Built-in command: (re)load the panel.
static bool do_tile_cache_reload(const SGPropertyNode *arg, SGPropertyNode *root)
Reload the tile cache.
static bool do_reposition(const SGPropertyNode *arg, SGPropertyNode *root)
static bool do_dialog_toggle(const SGPropertyNode *arg, SGPropertyNode *root)
Built-in command: Show an XML-configured dialog.
static bool do_open_browser(const SGPropertyNode *arg, SGPropertyNode *root)
static bool do_dialog_show(const SGPropertyNode *arg, SGPropertyNode *root)
Built-in command: Show an XML-configured dialog.
static bool do_exit(const SGPropertyNode *arg, SGPropertyNode *root)
Built-in command: exit FlightGear.
static bool do_dialog_update(const SGPropertyNode *arg, SGPropertyNode *root)
Update a value in the active XML-configured dialog.
static bool do_dialog_new(const SGPropertyNode *arg, SGPropertyNode *root)
Built-in command: Add a dialog to the GUI system.
static bool do_materials_reload(const SGPropertyNode *arg, SGPropertyNode *root)
Reload the materials definition.
static bool do_dialog_close(const SGPropertyNode *arg, SGPropertyNode *root)
Built-in Command: Hide the active XML-configured dialog.
static bool do_dump_terrain_branch(const SGPropertyNode *, SGPropertyNode *)
static bool do_release_cockpit_button(const SGPropertyNode *arg, SGPropertyNode *root)
static bool do_dialog_apply(const SGPropertyNode *arg, SGPropertyNode *root)
Apply a value in the active XML-configured dialog.
static bool do_dump_scene_graph(const SGPropertyNode *, SGPropertyNode *)
static bool do_presets_commit(const SGPropertyNode *arg, SGPropertyNode *root)
Built-in command: commit presets (read from in /sim/presets/)
static bool do_add_model(const SGPropertyNode *arg, SGPropertyNode *root)
Adds model to the scenery.
static bool do_reload_shaders(const SGPropertyNode *, SGPropertyNode *)
static bool do_screen_capture(const SGPropertyNode *, SGPropertyNode *)
Built-in command: capture screen.
static bool do_reload_compositor(const SGPropertyNode *, SGPropertyNode *)
Reload all Compositor instances in the default CameraGroup.
static bool do_gui_redraw(const SGPropertyNode *arg, SGPropertyNode *root)
Redraw GUI (applying new widget colors).
FGGlobals * globals
Definition globals.cxx:142
bool fgDumpSnapShot()
void fgDumpSceneGraph()
void fgDumpTerrainBranch()
void fgPrintVisibleSceneInfoCommand()
bool openBrowser(const std::string &address)
void fgResetIdleState()
Definition main.cxx:446
bool runInAppLauncherDialog()
void reloadCompositors(CameraGroup *cgroup)
Force a reload of all Compositor instances in the CameraGroup, except the one used by the GUI camera.
bool initPosition()
bool fgSetDouble(const char *name, double defaultValue)
Set a double value for a property.
Definition proptest.cpp:31
bool fgGetBool(char const *name, bool def)
Get a bool value for a property.
Definition proptest.cpp:25
bool fgSetBool(char const *name, bool val)
Set a bool value for a property.
Definition proptest.cpp:24
double fgGetDouble(const char *name, double defaultValue)
Get a double value for a property.
Definition proptest.cpp:30
bool fgSetString(char const *name, char const *str)
Set a string value for a property.
Definition proptest.cpp:26
SGPropertyNode * fgGetNode(const char *path, bool create)
Get a property node.
Definition proptest.cpp:27