#include <simgear/canvas/VGInitOperation.hxx>
#include <simgear/scene/model/modellib.hxx>
#include <simgear/scene/material/matlib.hxx>
+#include <simgear/scene/material/Effect.hxx>
#include <simgear/props/AtomicChangeListener.hxx>
#include <simgear/props/props.hxx>
#include <simgear/timing/sg_time.hxx>
#include "fg_props.hxx"
#include "positioninit.hxx"
#include "subsystemFactory.hxx"
+#include "options.hxx"
using namespace flightgear;
{
frame_signal->fireValueChanged();
- SG_LOG( SG_GENERAL, SG_DEBUG, "Running Main Loop");
- SG_LOG( SG_GENERAL, SG_DEBUG, "======= ==== ====");
-
// compute simulated time (allowing for pause, warp, etc) and
// real elapsed time
double sim_dt, real_dt;
globals->get_subsystem_mgr()->update(sim_dt);
simgear::AtomicChangeListener::fireChangeListeners();
-
- SG_LOG( SG_GENERAL, SG_DEBUG, "" );
}
+static void initTerrasync()
+{
+ if (fgGetBool("/sim/fghome-readonly", false)) {
+ return;
+ }
+
+ // start TerraSync up now, so it can be synchronizing shared models
+ // and airports data in parallel with a nav-cache rebuild.
+ SGPath tsyncCache(globals->get_fg_home());
+ tsyncCache.append("terrasync-cache.xml");
+
+ // wipe the cache file if requested
+ if (flightgear::Options::sharedInstance()->isOptionSet("restore-defaults")) {
+ SG_LOG(SG_GENERAL, SG_INFO, "restore-defaults requested, wiping terrasync update cache at " <<
+ tsyncCache);
+ if (tsyncCache.exists()) {
+ tsyncCache.remove();
+ }
+ }
+
+ fgSetString("/sim/terrasync/cache-path", tsyncCache.c_str());
+
+ simgear::SGTerraSync* terra_sync = new simgear::SGTerraSync();
+ terra_sync->setRoot(globals->get_props());
+ globals->add_subsystem("terrasync", terra_sync);
+
+ terra_sync->bind();
+ terra_sync->init();
+
+ // add the terrasync root as a data path so data can be retrieved from it
+ std::string terraSyncDir(fgGetString("/sim/terrasync/scenery-dir"));
+ globals->append_data_path(terraSyncDir);
+}
static void registerMainLoop()
{
// per pass) and once everything has been initialized fgMainLoop from
// then on.
+static int idle_state = 0;
+
static void fgIdleFunction ( void ) {
// Specify our current idle function state. This is used to run all
// our initializations out of the idle callback so that we can get a
// splash screen up and running right away.
- static int idle_state = 0;
-
+
if ( idle_state == 0 ) {
if (guiInit())
{
}
} else if ( idle_state == 2 ) {
+ initTerrasync();
idle_state++;
fgSplashProgress("loading-nav-dat");
}
} else if ( idle_state == 4 ) {
- idle_state+=2;
- // based on the requested presets, calculate the true starting
- // lon, lat
- flightgear::initPosition();
- flightgear::initTowerLocationListener();
+ idle_state++;
TimeManager* t = new TimeManager;
globals->add_subsystem("time", t, SGSubsystemMgr::INIT);
- t->init(); // need to init now, not during initSubsystems
// Do some quick general initializations
if( !fgInitGeneral()) {
- SG_LOG( SG_GENERAL, SG_ALERT,
- "General initialization failed ..." );
- exit(-1);
+ throw sg_exception("General initialization failed");
}
////////////////////////////////////////////////////////////////////
// Initialize the material manager
////////////////////////////////////////////////////////////////////
globals->set_matlib( new SGMaterialLib );
- simgear::SGModelLib::init(globals->get_fg_root(), globals->get_props());
simgear::SGModelLib::setPanelFunc(FGPanelNode::load);
-
+
+ } else if (( idle_state == 5 ) || (idle_state == 2005)) {
+ idle_state+=2;
+ flightgear::initPosition();
+ flightgear::initTowerLocationListener();
+
+ simgear::SGModelLib::init(globals->get_fg_root(), globals->get_props());
+
+ TimeManager* timeManager = (TimeManager*) globals->get_subsystem("time");
+ timeManager->init();
+
////////////////////////////////////////////////////////////////////
// Initialize the TG scenery subsystem.
////////////////////////////////////////////////////////////////////
- simgear::SGTerraSync* terra_sync = new simgear::SGTerraSync(globals->get_props());
- globals->add_subsystem("terrasync", terra_sync);
+
globals->set_scenery( new FGScenery );
globals->get_scenery()->init();
globals->get_scenery()->bind();
globals->set_tile_mgr( new FGTileMgr );
-
- fgSplashProgress("loading-aircraft");
-
- } else if ( idle_state == 6 ) {
- idle_state++;
+
fgSplashProgress("creating-subsystems");
-
- } else if ( idle_state == 7 ) {
- idle_state++;
+ } else if (( idle_state == 7 ) || (idle_state == 2007)) {
+ bool isReset = (idle_state == 2007);
+ idle_state = 8; // from the next state on, reset & startup are identical
SGTimeStamp st;
st.stamp();
- fgCreateSubsystems();
+ fgCreateSubsystems(isReset);
SG_LOG(SG_GENERAL, SG_INFO, "Creating subsystems took:" << st.elapsedMSec());
fgSplashProgress("binding-subsystems");
} else if ( idle_state == 10 ) {
idle_state = 900;
fgPostInitSubsystems();
-
- // Torsten Dreyer:
- // ugly hack for automatic runway selection on startup based on
- // metar data. Makes startup.nas obsolete and guarantees the same
- // runway selection as for AI traffic. However, this code belongs to
- // somewhere(?) else - if I only new where...
- if( true == fgGetBool( "/environment/metar/valid" ) ) {
- SG_LOG(SG_ENVIRONMENT, SG_INFO,
- "Using METAR for runway selection: '" << fgGetString("/environment/metar/data") << "'" );
- // the realwx_ctrl fetches metar in the foreground on init,
- // If it was able to fetch a metar or one was given on the commandline,
- // the valid flag is set here, otherwise it is false
- double hdg = fgGetDouble( "/environment/metar/base-wind-dir-deg", 9999.0 );
- string apt = fgGetString( "/sim/startup/options/airport" );
- string rwy = fgGetString( "/sim/startup/options/runway" );
- double strthdg = fgGetDouble( "/sim/startup/options/heading-deg", 9999.0 );
- string parkpos = fgGetString( "/sim/presets/parkpos" );
- bool onground = fgGetBool( "/sim/presets/onground", false );
- // don't check for wind-speed < 1kt, this belongs to the runway-selection code
- // the other logic is taken from former startup.nas
- if( hdg < 360.0 && apt.length() > 0 && strthdg > 360.0 && rwy.length() == 0 && onground && parkpos.length() == 0 ) {
- extern bool fgSetPosFromAirportIDandHdg( const string& id, double tgt_hdg );
- flightgear::setPosFromAirportIDandHdg( apt, hdg );
- }
- } else {
- SG_LOG(SG_ENVIRONMENT, SG_INFO,
- "No METAR available to pick active runway" );
- }
-
- fgSplashProgress("init-graphics");
-
+ fgSplashProgress("finalize-position");
} else if ( idle_state == 900 ) {
idle_state = 1000;
fgSetBool("sim/sceneryloaded", false);
registerMainLoop();
}
+
+ if ( idle_state == 2000 ) {
+ fgStartNewReset();
+ idle_state = 2005;
+ }
+}
+
+void fgResetIdleState()
+{
+ idle_state = 2000;
+ fgRegisterIdleHandler( &fgIdleFunction );
}
+
static void upper_case_property(const char *name)
{
using namespace simgear;
else
assert(t == props::STRING);
}
- p->addChangeListener(new FGMakeUpperCase);
+ SGPropertyChangeListener* muc = new FGMakeUpperCase;
+ globals->addListenerToCleanup(muc);
+ p->addChangeListener(muc);
+}
+
+// see http://code.google.com/p/flightgear-bugs/issues/detail?id=385
+// for the details of this.
+static void ATIScreenSizeHack()
+{
+ osg::ref_ptr<osg::Camera> hackCam = new osg::Camera;
+ hackCam->setRenderOrder(osg::Camera::PRE_RENDER);
+ int prettyMuchAnyInt = 1;
+ hackCam->setViewport(0, 0, prettyMuchAnyInt, prettyMuchAnyInt);
+ globals->get_renderer()->addCamera(hackCam, false);
}
+// Propose NVIDIA Optimus to use high-end GPU
+#if defined(SG_WINDOWS)
+extern "C" {
+ _declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001;
+}
+#endif
+
+static void logToFile()
+{
+ SGPath logPath = globals->get_fg_home();
+ logPath.append("fgfs.log");
+ if (logPath.exists()) {
+ SGPath prevLogPath = globals->get_fg_home();
+ prevLogPath.append("fgfs_0.log");
+ logPath.rename(prevLogPath);
+ // bit strange, we need to restore the correct value of logPath now
+ logPath = globals->get_fg_home();
+ logPath.append("fgfs.log");
+ }
+ sglog().logToFile(logPath, SG_ALL, SG_INFO);
+}
// Main top level initialization
int fgMainInit( int argc, char **argv ) {
// set default log levels
sglog().setLogLevels( SG_ALL, SG_ALERT );
- string version;
+ globals = new FGGlobals;
+ if (!fgInitHome()) {
+ return EXIT_FAILURE;
+ }
+
+ if (!fgGetBool("/sim/fghome-readonly")) {
+ // now home is initialised, we can log to a file inside it
+ logToFile();
+ }
+
+ std::string version;
#ifdef FLIGHTGEAR_VERSION
version = FLIGHTGEAR_VERSION;
#else
// Allocate global data structures. This needs to happen before
// we parse command line options
- globals = new FGGlobals;
-
+
+
// seed the random number generator
sg_srandom_time();
// Load the configuration parameters. (Command line options
// override config file options. Config file options override
// defaults.)
- if ( !fgInitConfig(argc, argv) ) {
- SG_LOG( SG_GENERAL, SG_ALERT, "Config option parsing failed ..." );
- exit(-1);
+ int configResult = fgInitConfig(argc, argv, false);
+ if (configResult == flightgear::FG_OPTIONS_ERROR) {
+ return EXIT_FAILURE;
+ } else if (configResult == flightgear::FG_OPTIONS_EXIT) {
+ return EXIT_SUCCESS;
}
-
+
+ configResult = fgInitAircraft(false);
+ if (configResult == flightgear::FG_OPTIONS_ERROR) {
+ return EXIT_FAILURE;
+ } else if (configResult == flightgear::FG_OPTIONS_EXIT) {
+ return EXIT_SUCCESS;
+ }
+
+ configResult = flightgear::Options::sharedInstance()->processOptions();
+ if (configResult == flightgear::FG_OPTIONS_ERROR) {
+ return EXIT_FAILURE;
+ } else if (configResult == flightgear::FG_OPTIONS_EXIT) {
+ return EXIT_SUCCESS;
+ }
+
// Initialize the Window/Graphics environment.
fgOSInit(&argc, argv);
_bootstrap_OSInit++;
// Clouds3D requires an alpha channel
fgOSOpenWindow(true /* request stencil buffer */);
-
+ fgOSResetProperties();
+
// Initialize the splash screen right away
fntInit();
fgSplashInit();
+ if (fgGetBool("/sim/ati-viewport-hack", true)) {
+ SG_LOG(SG_GENERAL, SG_ALERT, "Enabling ATI viewport hack");
+ ATIScreenSizeHack();
+ }
+
+ fgOutputSettings();
+
// pass control off to the master event handler
int result = fgOSMainLoop();
+ frame_signal.clear();
+ fgOSCloseWindow();
+
+ simgear::clearEffectCache();
// clean up here; ensure we null globals to avoid
// confusing the atexit() handler