Merge branch 'next' of D:\Git_New\flightgear into next
This commit is contained in:
commit
63ec4f3f6c
18 changed files with 704 additions and 616 deletions
|
@ -4512,11 +4512,11 @@
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\..\src\Time\TimeManager.cxx"
|
RelativePath="..\..\..\src\Time\tmp.cxx"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\..\src\Time\TimeManager.hxx"
|
RelativePath="..\..\..\src\Time\tmp.hxx"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
</Filter>
|
</Filter>
|
||||||
|
|
|
@ -95,6 +95,13 @@ void FGInstrumentMgr::init()
|
||||||
set_subsystem("gps[0]", new GPS(nd));
|
set_subsystem("gps[0]", new GPS(nd));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// bind() created instruments before init.
|
||||||
|
for (unsigned int i=0; i<_instruments.size(); ++i) {
|
||||||
|
const std::string& nm(_instruments[i]);
|
||||||
|
SGSubsystem* instr = get_subsystem(nm);
|
||||||
|
instr->bind();
|
||||||
|
}
|
||||||
|
|
||||||
SGSubsystemGroup::init();
|
SGSubsystemGroup::init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,6 +37,7 @@
|
||||||
#include <Scripting/NasalSys.hxx>
|
#include <Scripting/NasalSys.hxx>
|
||||||
#include <Sound/sample_queue.hxx>
|
#include <Sound/sample_queue.hxx>
|
||||||
#include <Time/sunsolver.hxx>
|
#include <Time/sunsolver.hxx>
|
||||||
|
#include <Time/tmp.hxx>
|
||||||
|
|
||||||
#include "fg_init.hxx"
|
#include "fg_init.hxx"
|
||||||
#include "fg_io.hxx"
|
#include "fg_io.hxx"
|
||||||
|
|
|
@ -62,6 +62,8 @@
|
||||||
#include <simgear/scene/material/matlib.hxx>
|
#include <simgear/scene/material/matlib.hxx>
|
||||||
#include <simgear/scene/model/particles.hxx>
|
#include <simgear/scene/model/particles.hxx>
|
||||||
#include <simgear/sound/soundmgr_openal.hxx>
|
#include <simgear/sound/soundmgr_openal.hxx>
|
||||||
|
#include <simgear/timing/sg_time.hxx>
|
||||||
|
#include <simgear/timing/lowleveltime.h>
|
||||||
|
|
||||||
#include <Aircraft/controls.hxx>
|
#include <Aircraft/controls.hxx>
|
||||||
#include <Aircraft/replay.hxx>
|
#include <Aircraft/replay.hxx>
|
||||||
|
@ -105,6 +107,8 @@
|
||||||
#include <Sound/voice.hxx>
|
#include <Sound/voice.hxx>
|
||||||
#include <Systems/system_mgr.hxx>
|
#include <Systems/system_mgr.hxx>
|
||||||
#include <Time/light.hxx>
|
#include <Time/light.hxx>
|
||||||
|
#include <Time/sunsolver.hxx>
|
||||||
|
#include <Time/tmp.hxx>
|
||||||
#include <Traffic/TrafficMgr.hxx>
|
#include <Traffic/TrafficMgr.hxx>
|
||||||
#include <MultiPlayer/multiplaymgr.hxx>
|
#include <MultiPlayer/multiplaymgr.hxx>
|
||||||
#include <FDM/fdm_shell.hxx>
|
#include <FDM/fdm_shell.hxx>
|
||||||
|
@ -1268,6 +1272,140 @@ void fgInitView() {
|
||||||
globals->get_viewmgr()->update(0);
|
globals->get_viewmgr()->update(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SGTime *fgInitTime() {
|
||||||
|
// Initialize time
|
||||||
|
static const SGPropertyNode *longitude
|
||||||
|
= fgGetNode("/position/longitude-deg");
|
||||||
|
static const SGPropertyNode *latitude
|
||||||
|
= fgGetNode("/position/latitude-deg");
|
||||||
|
static const SGPropertyNode *cur_time_override
|
||||||
|
= fgGetNode("/sim/time/cur-time-override", true);
|
||||||
|
|
||||||
|
SGPath zone( globals->get_fg_root() );
|
||||||
|
zone.append( "Timezone" );
|
||||||
|
SGTime *t = new SGTime( longitude->getDoubleValue()
|
||||||
|
* SGD_DEGREES_TO_RADIANS,
|
||||||
|
latitude->getDoubleValue()
|
||||||
|
* SGD_DEGREES_TO_RADIANS,
|
||||||
|
zone.str(),
|
||||||
|
cur_time_override->getLongValue() );
|
||||||
|
|
||||||
|
globals->set_warp_delta( 0 );
|
||||||
|
|
||||||
|
t->update( 0.0, 0.0,
|
||||||
|
cur_time_override->getLongValue(),
|
||||||
|
globals->get_warp() );
|
||||||
|
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// set up a time offset (aka warp) if one is specified
|
||||||
|
void fgInitTimeOffset() {
|
||||||
|
static const SGPropertyNode *longitude
|
||||||
|
= fgGetNode("/position/longitude-deg");
|
||||||
|
static const SGPropertyNode *latitude
|
||||||
|
= fgGetNode("/position/latitude-deg");
|
||||||
|
static const SGPropertyNode *cur_time_override
|
||||||
|
= fgGetNode("/sim/time/cur-time-override", true);
|
||||||
|
|
||||||
|
// Handle potential user specified time offsets
|
||||||
|
int orig_warp = globals->get_warp();
|
||||||
|
SGTime *t = globals->get_time_params();
|
||||||
|
time_t cur_time = t->get_cur_time();
|
||||||
|
time_t currGMT = sgTimeGetGMT( gmtime(&cur_time) );
|
||||||
|
time_t systemLocalTime = sgTimeGetGMT( localtime(&cur_time) );
|
||||||
|
time_t aircraftLocalTime =
|
||||||
|
sgTimeGetGMT( fgLocaltime(&cur_time, t->get_zonename() ) );
|
||||||
|
|
||||||
|
// Okay, we now have several possible scenarios
|
||||||
|
int offset = fgGetInt("/sim/startup/time-offset");
|
||||||
|
string offset_type = fgGetString("/sim/startup/time-offset-type");
|
||||||
|
|
||||||
|
int warp = 0;
|
||||||
|
if ( offset_type == "real" ) {
|
||||||
|
warp = 0;
|
||||||
|
} 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 );
|
||||||
|
} else if ( offset_type == "system-offset" ) {
|
||||||
|
warp = offset;
|
||||||
|
orig_warp = 0;
|
||||||
|
} else if ( offset_type == "gmt-offset" ) {
|
||||||
|
warp = offset - (currGMT - systemLocalTime);
|
||||||
|
orig_warp = 0;
|
||||||
|
} else if ( offset_type == "latitude-offset" ) {
|
||||||
|
warp = offset - (aircraftLocalTime - systemLocalTime);
|
||||||
|
orig_warp = 0;
|
||||||
|
} else if ( offset_type == "system" ) {
|
||||||
|
warp = offset - (systemLocalTime - currGMT) - cur_time;
|
||||||
|
} else if ( offset_type == "gmt" ) {
|
||||||
|
warp = offset - cur_time;
|
||||||
|
} else if ( offset_type == "latitude" ) {
|
||||||
|
warp = offset - (aircraftLocalTime - currGMT)- cur_time;
|
||||||
|
} else {
|
||||||
|
SG_LOG( SG_GENERAL, SG_ALERT,
|
||||||
|
"FG_TIME::Unsupported offset type " << offset_type );
|
||||||
|
exit( -1 );
|
||||||
|
}
|
||||||
|
globals->set_warp( orig_warp + warp );
|
||||||
|
t->update( longitude->getDoubleValue() * SGD_DEGREES_TO_RADIANS,
|
||||||
|
latitude->getDoubleValue() * SGD_DEGREES_TO_RADIANS,
|
||||||
|
cur_time_override->getLongValue(),
|
||||||
|
globals->get_warp() );
|
||||||
|
|
||||||
|
SG_LOG( SG_GENERAL, SG_INFO, "After fgInitTimeOffset(): warp = "
|
||||||
|
<< globals->get_warp() );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// This is the top level init routine which calls all the other
|
// This is the top level init routine which calls all the other
|
||||||
// initialization routines. If you are adding a subsystem to flight
|
// initialization routines. If you are adding a subsystem to flight
|
||||||
// gear, its initialization call should located in this routine.
|
// gear, its initialization call should located in this routine.
|
||||||
|
@ -1390,6 +1528,17 @@ bool fgInitSubsystems() {
|
||||||
|
|
||||||
globals->add_subsystem("gui", new NewGUI, SGSubsystemMgr::INIT);
|
globals->add_subsystem("gui", new NewGUI, SGSubsystemMgr::INIT);
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Initialize the local time subsystem.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// update the current timezone each 30 minutes
|
||||||
|
globals->get_event_mgr()->addTask( "fgUpdateLocalTime()",
|
||||||
|
&fgUpdateLocalTime, 30*60 );
|
||||||
|
fgInitTimeOffset(); // the environment subsystem needs this
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Initialize the lighting subsystem.
|
// Initialize the lighting subsystem.
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
|
@ -1565,7 +1714,10 @@ void fgReInitSubsystems()
|
||||||
|
|
||||||
globals->get_controls()->reset_all();
|
globals->get_controls()->reset_all();
|
||||||
|
|
||||||
globals->get_subsystem("time")->reinit();
|
fgUpdateLocalTime();
|
||||||
|
|
||||||
|
// re-init to proper time of day setting
|
||||||
|
fgInitTimeOffset();
|
||||||
|
|
||||||
if ( !freeze ) {
|
if ( !freeze ) {
|
||||||
fgSetBool("/sim/freeze/master", false);
|
fgSetBool("/sim/freeze/master", false);
|
||||||
|
@ -1591,6 +1743,11 @@ void doSimulatorReset(void) // from gui_local.cxx -- TODO merge with fgReInitSu
|
||||||
// update our position based on current presets
|
// update our position based on current presets
|
||||||
fgInitPosition();
|
fgInitPosition();
|
||||||
|
|
||||||
|
SGTime *t = globals->get_time_params();
|
||||||
|
delete t;
|
||||||
|
t = fgInitTime();
|
||||||
|
globals->set_time_params(t);
|
||||||
|
|
||||||
fgReInitSubsystems();
|
fgReInitSubsystems();
|
||||||
|
|
||||||
globals->get_tile_mgr()->update(fgGetDouble("/environment/visibility-m"));
|
globals->get_tile_mgr()->update(fgGetDouble("/environment/visibility-m"));
|
||||||
|
|
|
@ -79,6 +79,14 @@ bool fgInitPosition();
|
||||||
// Listen to /sim/tower/airport-id and set tower view position accordingly
|
// Listen to /sim/tower/airport-id and set tower view position accordingly
|
||||||
void fgInitTowerLocationListener();
|
void fgInitTowerLocationListener();
|
||||||
|
|
||||||
|
|
||||||
|
// Initialize various time dependent systems (lighting, sun position, etc.)
|
||||||
|
// returns a new instance of the SGTime class
|
||||||
|
SGTime *fgInitTime();
|
||||||
|
|
||||||
|
// set up a time offset (aka warp) if one is specified
|
||||||
|
void fgInitTimeOffset();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Search in the current directory, and in on directory deeper
|
* Search in the current directory, and in on directory deeper
|
||||||
* for <aircraft>-set.xml configuration files and show the aircaft name
|
* for <aircraft>-set.xml configuration files and show the aircaft name
|
||||||
|
|
|
@ -34,6 +34,8 @@
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
|
#include <plib/netSocket.h>
|
||||||
|
|
||||||
#include <osg/Camera>
|
#include <osg/Camera>
|
||||||
#include <osg/GraphicsContext>
|
#include <osg/GraphicsContext>
|
||||||
#include <osgDB/Registry>
|
#include <osgDB/Registry>
|
||||||
|
@ -65,7 +67,7 @@
|
||||||
#include <Sound/fg_fx.hxx>
|
#include <Sound/fg_fx.hxx>
|
||||||
#include <ATCDCL/ATCmgr.hxx>
|
#include <ATCDCL/ATCmgr.hxx>
|
||||||
#include <ATCDCL/AIMgr.hxx>
|
#include <ATCDCL/AIMgr.hxx>
|
||||||
#include <Time/TimeManager.hxx>
|
#include <Time/tmp.hxx>
|
||||||
#include <Environment/environment_mgr.hxx>
|
#include <Environment/environment_mgr.hxx>
|
||||||
#include <Environment/ephemeris.hxx>
|
#include <Environment/ephemeris.hxx>
|
||||||
#include <GUI/new_gui.hxx>
|
#include <GUI/new_gui.hxx>
|
||||||
|
@ -83,6 +85,8 @@
|
||||||
#include "WindowSystemAdapter.hxx"
|
#include "WindowSystemAdapter.hxx"
|
||||||
#include <Main/viewer.hxx>
|
#include <Main/viewer.hxx>
|
||||||
|
|
||||||
|
static double real_delta_time_sec = 0.0;
|
||||||
|
double delta_time_sec = 0.0;
|
||||||
|
|
||||||
using namespace flightgear;
|
using namespace flightgear;
|
||||||
|
|
||||||
|
@ -95,7 +99,10 @@ FGGeneral general;
|
||||||
// our initializations out of the idle callback so that we can get a
|
// our initializations out of the idle callback so that we can get a
|
||||||
// splash screen up and running right away.
|
// splash screen up and running right away.
|
||||||
int idle_state = 0;
|
int idle_state = 0;
|
||||||
|
long global_multi_loop;
|
||||||
|
|
||||||
|
SGTimeStamp last_time_stamp;
|
||||||
|
SGTimeStamp current_time_stamp;
|
||||||
|
|
||||||
void fgInitSoundManager();
|
void fgInitSoundManager();
|
||||||
void fgSetNewSoundDevice(const char *);
|
void fgSetNewSoundDevice(const char *);
|
||||||
|
@ -107,7 +114,8 @@ extern int _bootstrap_OSInit;
|
||||||
// What should we do when we have nothing else to do? Let's get ready
|
// What should we do when we have nothing else to do? Let's get ready
|
||||||
// for the next move and update the display?
|
// for the next move and update the display?
|
||||||
static void fgMainLoop( void ) {
|
static void fgMainLoop( void ) {
|
||||||
|
int model_hz = fgGetInt("/sim/model-hz");
|
||||||
|
|
||||||
static SGConstPropertyNode_ptr longitude
|
static SGConstPropertyNode_ptr longitude
|
||||||
= fgGetNode("/position/longitude-deg");
|
= fgGetNode("/position/longitude-deg");
|
||||||
static SGConstPropertyNode_ptr latitude
|
static SGConstPropertyNode_ptr latitude
|
||||||
|
@ -120,24 +128,172 @@ static void fgMainLoop( void ) {
|
||||||
= fgGetNode("/velocities/speed-east-fps");
|
= fgGetNode("/velocities/speed-east-fps");
|
||||||
static SGConstPropertyNode_ptr vd_fps
|
static SGConstPropertyNode_ptr vd_fps
|
||||||
= fgGetNode("/velocities/speed-down-fps");
|
= fgGetNode("/velocities/speed-down-fps");
|
||||||
|
static SGConstPropertyNode_ptr clock_freeze
|
||||||
|
= fgGetNode("/sim/freeze/clock", true);
|
||||||
|
static SGConstPropertyNode_ptr cur_time_override
|
||||||
|
= fgGetNode("/sim/time/cur-time-override", true);
|
||||||
|
static SGConstPropertyNode_ptr max_simtime_per_frame
|
||||||
|
= fgGetNode("/sim/max-simtime-per-frame", true);
|
||||||
static SGPropertyNode_ptr frame_signal
|
static SGPropertyNode_ptr frame_signal
|
||||||
= fgGetNode("/sim/signals/frame", true);
|
= fgGetNode("/sim/signals/frame", true);
|
||||||
|
|
||||||
frame_signal->fireValueChanged();
|
frame_signal->fireValueChanged();
|
||||||
SGCloudLayer::enable_bump_mapping = fgGetBool("/sim/rendering/bump-mapping");
|
SGCloudLayer::enable_bump_mapping = fgGetBool("/sim/rendering/bump-mapping");
|
||||||
|
|
||||||
|
bool scenery_loaded = fgGetBool("sim/sceneryloaded");
|
||||||
|
bool wait_for_scenery = !(scenery_loaded || fgGetBool("sim/sceneryloaded-override"));
|
||||||
|
|
||||||
|
// Update the elapsed time.
|
||||||
|
static bool first_time = true;
|
||||||
|
if ( first_time ) {
|
||||||
|
last_time_stamp.stamp();
|
||||||
|
first_time = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
double throttle_hz = fgGetDouble("/sim/frame-rate-throttle-hz", 0.0);
|
||||||
|
if ( throttle_hz > 0.0 && !wait_for_scenery ) {
|
||||||
|
// optionally throttle the frame rate (to get consistent frame
|
||||||
|
// rates or reduce cpu usage.
|
||||||
|
|
||||||
|
double frame_us = 1000000.0 / throttle_hz;
|
||||||
|
|
||||||
|
#define FG_SLEEP_BASED_TIMING 1
|
||||||
|
#if defined(FG_SLEEP_BASED_TIMING)
|
||||||
|
// sleep based timing loop.
|
||||||
|
//
|
||||||
|
// Calling sleep, even usleep() on linux is less accurate than
|
||||||
|
// we like, but it does free up the cpu for other tasks during
|
||||||
|
// the sleep so it is desirable. Because of the way sleep()
|
||||||
|
// is implemented in consumer operating systems like windows
|
||||||
|
// and linux, you almost always sleep a little longer than the
|
||||||
|
// requested amount.
|
||||||
|
//
|
||||||
|
// To combat the problem of sleeping too long, we calculate the
|
||||||
|
// desired wait time and shorten it by 2000us (2ms) to avoid
|
||||||
|
// [hopefully] over-sleep'ing. The 2ms value was arrived at
|
||||||
|
// via experimentation. We follow this up at the end with a
|
||||||
|
// simple busy-wait loop to get the final pause timing exactly
|
||||||
|
// right.
|
||||||
|
//
|
||||||
|
// Assuming we don't oversleep by more than 2000us, this
|
||||||
|
// should be a reasonable compromise between sleep based
|
||||||
|
// waiting, and busy waiting.
|
||||||
|
|
||||||
|
// sleep() will always overshoot by a bit so undersleep by
|
||||||
|
// 2000us in the hopes of never oversleeping.
|
||||||
|
frame_us -= 2000.0;
|
||||||
|
if ( frame_us < 0.0 ) {
|
||||||
|
frame_us = 0.0;
|
||||||
|
}
|
||||||
|
current_time_stamp.stamp();
|
||||||
|
/* Convert to ms */
|
||||||
|
double elapsed_us = (current_time_stamp - last_time_stamp).toUSecs();
|
||||||
|
if ( elapsed_us < frame_us ) {
|
||||||
|
double requested_us = frame_us - elapsed_us;
|
||||||
|
ulMilliSecondSleep ( (int)(requested_us / 1000.0) ) ;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// busy wait timing loop.
|
||||||
|
//
|
||||||
|
// This yields the most accurate timing. If the previous
|
||||||
|
// ulMilliSecondSleep() call is omitted this will peg the cpu
|
||||||
|
// (which is just fine if FG is the only app you care about.)
|
||||||
|
current_time_stamp.stamp();
|
||||||
|
SGTimeStamp next_time_stamp = last_time_stamp;
|
||||||
|
next_time_stamp += SGTimeStamp::fromSec(1e-6*frame_us);
|
||||||
|
while ( current_time_stamp < next_time_stamp ) {
|
||||||
|
current_time_stamp.stamp();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// run as fast as the app will go
|
||||||
|
current_time_stamp.stamp();
|
||||||
|
}
|
||||||
|
|
||||||
|
real_delta_time_sec = (current_time_stamp - last_time_stamp).toSecs();
|
||||||
|
|
||||||
|
// Limit the time we need to spend in simulation loops
|
||||||
|
// That means, if the /sim/max-simtime-per-frame value is strictly positive
|
||||||
|
// you can limit the maximum amount of time you will do simulations for
|
||||||
|
// one frame to display. The cpu time spent in simulations code is roughly
|
||||||
|
// at least O(real_delta_time_sec). If this is (due to running debug
|
||||||
|
// builds or valgrind or something different blowing up execution times)
|
||||||
|
// larger than the real time you will no longer get any response
|
||||||
|
// from flightgear. This limits that effect. Just set to property from
|
||||||
|
// your .fgfsrc or commandline ...
|
||||||
|
double dtMax = max_simtime_per_frame->getDoubleValue();
|
||||||
|
if (0 < dtMax && dtMax < real_delta_time_sec)
|
||||||
|
real_delta_time_sec = dtMax;
|
||||||
|
|
||||||
|
SGSubsystemGroup* fdmGroup =
|
||||||
|
globals->get_subsystem_mgr()->get_group(SGSubsystemMgr::FDM);
|
||||||
|
fdmGroup->set_fixed_update_time(1.0 / model_hz);
|
||||||
|
|
||||||
|
// round the real time down to a multiple of 1/model-hz.
|
||||||
|
// this way all systems are updated the _same_ amount of dt.
|
||||||
|
static double reminder = 0.0;
|
||||||
|
real_delta_time_sec += reminder;
|
||||||
|
global_multi_loop = long(floor(real_delta_time_sec*model_hz));
|
||||||
|
global_multi_loop = SGMisc<long>::max(0, global_multi_loop);
|
||||||
|
reminder = real_delta_time_sec - double(global_multi_loop)/double(model_hz);
|
||||||
|
real_delta_time_sec = double(global_multi_loop)/double(model_hz);
|
||||||
|
|
||||||
|
if (clock_freeze->getBoolValue() || wait_for_scenery) {
|
||||||
|
delta_time_sec = 0;
|
||||||
|
} else {
|
||||||
|
delta_time_sec = real_delta_time_sec;
|
||||||
|
}
|
||||||
|
last_time_stamp = current_time_stamp;
|
||||||
|
globals->inc_sim_time_sec( delta_time_sec );
|
||||||
|
|
||||||
|
// These are useful, especially for Nasal scripts.
|
||||||
|
fgSetDouble("/sim/time/delta-realtime-sec", real_delta_time_sec);
|
||||||
|
fgSetDouble("/sim/time/delta-sec", delta_time_sec);
|
||||||
|
|
||||||
|
#ifdef FANCY_FRAME_COUNTER
|
||||||
|
int i;
|
||||||
|
double accum;
|
||||||
|
#else
|
||||||
|
static time_t last_time = 0;
|
||||||
|
static int frames = 0;
|
||||||
|
#endif // FANCY_FRAME_COUNTER
|
||||||
|
|
||||||
|
SGTime *t = globals->get_time_params();
|
||||||
|
|
||||||
SG_LOG( SG_ALL, SG_DEBUG, "Running Main Loop");
|
SG_LOG( SG_ALL, SG_DEBUG, "Running Main Loop");
|
||||||
SG_LOG( SG_ALL, SG_DEBUG, "======= ==== ====");
|
SG_LOG( SG_ALL, SG_DEBUG, "======= ==== ====");
|
||||||
|
|
||||||
|
// update "time"
|
||||||
// update "time"
|
static bool last_clock_freeze = false;
|
||||||
double sim_dt, real_dt;
|
|
||||||
TimeManager* timeMgr = (TimeManager*) globals->get_subsystem("time");
|
if ( clock_freeze->getBoolValue() ) {
|
||||||
// compute simulated time (allowing for pause, warp, etc) and
|
// clock freeze requested
|
||||||
// real elapsed time
|
if ( cur_time_override->getLongValue() == 0 ) {
|
||||||
timeMgr->computeTimeDeltas(sim_dt, real_dt);
|
fgSetLong( "/sim/time/cur-time-override", t->get_cur_time() );
|
||||||
|
globals->set_warp( 0 );
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// no clock freeze requested
|
||||||
|
if ( last_clock_freeze == true ) {
|
||||||
|
// clock just unfroze, let's set warp as the difference
|
||||||
|
// between frozen time and current time so we don't get a
|
||||||
|
// time jump (and corresponding sky object and lighting
|
||||||
|
// jump.)
|
||||||
|
globals->set_warp( cur_time_override->getLongValue() - time(NULL) );
|
||||||
|
fgSetLong( "/sim/time/cur-time-override", 0 );
|
||||||
|
}
|
||||||
|
if ( globals->get_warp_delta() != 0 ) {
|
||||||
|
globals->inc_warp( globals->get_warp_delta() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
last_clock_freeze = clock_freeze->getBoolValue();
|
||||||
|
|
||||||
|
t->update( longitude->getDoubleValue() * SGD_DEGREES_TO_RADIANS,
|
||||||
|
latitude->getDoubleValue() * SGD_DEGREES_TO_RADIANS,
|
||||||
|
cur_time_override->getLongValue(),
|
||||||
|
globals->get_warp() );
|
||||||
|
|
||||||
if (globals->get_warp_delta() != 0) {
|
if (globals->get_warp_delta() != 0) {
|
||||||
FGLight *l = (FGLight *)(globals->get_subsystem("lighting"));
|
FGLight *l = (FGLight *)(globals->get_subsystem("lighting"));
|
||||||
l->update( 0.5 );
|
l->update( 0.5 );
|
||||||
|
@ -151,6 +307,36 @@ static void fgMainLoop( void ) {
|
||||||
altitude->getDoubleValue() * SG_FEET_TO_METER,
|
altitude->getDoubleValue() * SG_FEET_TO_METER,
|
||||||
globals->get_time_params()->getJD() );
|
globals->get_time_params()->getJD() );
|
||||||
|
|
||||||
|
// Calculate frame rate average
|
||||||
|
#ifdef FANCY_FRAME_COUNTER
|
||||||
|
/* old fps calculation */
|
||||||
|
if ( elapsed > 0 ) {
|
||||||
|
double tmp;
|
||||||
|
accum = 0.0;
|
||||||
|
for ( i = FG_FRAME_RATE_HISTORY - 2; i >= 0; i-- ) {
|
||||||
|
tmp = general.get_frame(i);
|
||||||
|
accum += tmp;
|
||||||
|
// printf("frame[%d] = %.2f\n", i, g->frames[i]);
|
||||||
|
general.set_frame(i+1,tmp);
|
||||||
|
}
|
||||||
|
tmp = 1000000.0 / (float)elapsed;
|
||||||
|
general.set_frame(0,tmp);
|
||||||
|
// printf("frame[0] = %.2f\n", general.frames[0]);
|
||||||
|
accum += tmp;
|
||||||
|
general.set_frame_rate(accum / (float)FG_FRAME_RATE_HISTORY);
|
||||||
|
// printf("ave = %.2f\n", general.frame_rate);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if ( (t->get_cur_time() != last_time) && (last_time > 0) ) {
|
||||||
|
general.set_frame_rate( frames );
|
||||||
|
fgSetInt("/sim/frame-rate", frames);
|
||||||
|
SG_LOG( SG_ALL, SG_DEBUG,
|
||||||
|
"--> Frame rate is = " << general.get_frame_rate() );
|
||||||
|
frames = 0;
|
||||||
|
}
|
||||||
|
last_time = t->get_cur_time();
|
||||||
|
++frames;
|
||||||
|
#endif
|
||||||
|
|
||||||
// Update any multiplayer's network queues, the AIMultiplayer
|
// Update any multiplayer's network queues, the AIMultiplayer
|
||||||
// implementation is an AI model and depends on that
|
// implementation is an AI model and depends on that
|
||||||
|
@ -159,7 +345,7 @@ static void fgMainLoop( void ) {
|
||||||
#if ENABLE_ATCDCL
|
#if ENABLE_ATCDCL
|
||||||
// Run ATC subsystem
|
// Run ATC subsystem
|
||||||
if (fgGetBool("/sim/atc/enabled"))
|
if (fgGetBool("/sim/atc/enabled"))
|
||||||
globals->get_ATC_mgr()->update(sim_dt);
|
globals->get_ATC_mgr()->update(delta_time_sec);
|
||||||
|
|
||||||
|
|
||||||
// Run the AI subsystem
|
// Run the AI subsystem
|
||||||
|
@ -170,11 +356,11 @@ static void fgMainLoop( void ) {
|
||||||
// depricated AI_mgr system. So, we can safely skip the following
|
// depricated AI_mgr system. So, we can safely skip the following
|
||||||
// two lines at compile time when compiling with --disable-atcdcl
|
// two lines at compile time when compiling with --disable-atcdcl
|
||||||
if (fgGetBool("/sim/ai-traffic/enabled"))
|
if (fgGetBool("/sim/ai-traffic/enabled"))
|
||||||
globals->get_AI_mgr()->update(sim_dt);
|
globals->get_AI_mgr()->update(delta_time_sec);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
globals->get_subsystem_mgr()->update(sim_dt);
|
globals->get_subsystem_mgr()->update(delta_time_sec);
|
||||||
globals->get_aircraft_model()->update(sim_dt);
|
globals->get_aircraft_model()->update(delta_time_sec);
|
||||||
|
|
||||||
//
|
//
|
||||||
// Tile Manager updates - see if we need to load any new scenery tiles.
|
// Tile Manager updates - see if we need to load any new scenery tiles.
|
||||||
|
@ -190,14 +376,14 @@ static void fgMainLoop( void ) {
|
||||||
globals->get_tile_mgr()->update(geodViewPos, visibility_meters);
|
globals->get_tile_mgr()->update(geodViewPos, visibility_meters);
|
||||||
|
|
||||||
// run Nasal's settimer() loops right before the view manager
|
// run Nasal's settimer() loops right before the view manager
|
||||||
globals->get_event_mgr()->update(sim_dt);
|
globals->get_event_mgr()->update(delta_time_sec);
|
||||||
|
|
||||||
// pick up model coordidnates that Nasal code may have set relative to the
|
// pick up model coordidnates that Nasal code may have set relative to the
|
||||||
// aircraft's
|
// aircraft's
|
||||||
globals->get_model_mgr()->update(sim_dt);
|
globals->get_model_mgr()->update(delta_time_sec);
|
||||||
|
|
||||||
// update the view angle as late as possible, but before sound calculations
|
// update the view angle as late as possible, but before sound calculations
|
||||||
globals->get_viewmgr()->update(real_dt);
|
globals->get_viewmgr()->update(real_delta_time_sec);
|
||||||
|
|
||||||
// Update the sound manager last so it can use the CPU while the GPU
|
// Update the sound manager last so it can use the CPU while the GPU
|
||||||
// is processing the scenery (doubled the frame-rate for me) -EMH-
|
// is processing the scenery (doubled the frame-rate for me) -EMH-
|
||||||
|
@ -233,13 +419,13 @@ static void fgMainLoop( void ) {
|
||||||
if (smgr_enabled == true) {
|
if (smgr_enabled == true) {
|
||||||
static SGPropertyNode *volume = fgGetNode("/sim/sound/volume");
|
static SGPropertyNode *volume = fgGetNode("/sim/sound/volume");
|
||||||
smgr->set_volume(volume->getFloatValue());
|
smgr->set_volume(volume->getFloatValue());
|
||||||
smgr->update(sim_dt);
|
smgr->update(delta_time_sec);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// END Tile Manager udpates
|
// END Tile Manager udpates
|
||||||
bool scenery_loaded = fgGetBool("sim/sceneryloaded");
|
|
||||||
if (!scenery_loaded && globals->get_tile_mgr()->isSceneryLoaded()
|
if (!scenery_loaded && globals->get_tile_mgr()->isSceneryLoaded()
|
||||||
&& fgGetBool("sim/fdm-initialized")) {
|
&& fgGetBool("sim/fdm-initialized")) {
|
||||||
fgSetBool("sim/sceneryloaded",true);
|
fgSetBool("sim/sceneryloaded",true);
|
||||||
|
@ -380,10 +566,9 @@ static void fgIdleFunction ( void ) {
|
||||||
fgInitPosition();
|
fgInitPosition();
|
||||||
fgInitTowerLocationListener();
|
fgInitTowerLocationListener();
|
||||||
|
|
||||||
TimeManager* t = new TimeManager;
|
SGTime *t = fgInitTime();
|
||||||
globals->add_subsystem("time", t, SGSubsystemMgr::INIT);
|
globals->set_time_params( t );
|
||||||
t->init(); // need to init now, not during initSubsystems
|
|
||||||
|
|
||||||
// Do some quick general initializations
|
// Do some quick general initializations
|
||||||
if( !fgInitGeneral()) {
|
if( !fgInitGeneral()) {
|
||||||
SG_LOG( SG_GENERAL, SG_ALERT,
|
SG_LOG( SG_GENERAL, SG_ALERT,
|
||||||
|
@ -548,7 +733,10 @@ static void fgIdleFunction ( void ) {
|
||||||
|
|
||||||
} else if ( idle_state == 8 ) {
|
} else if ( idle_state == 8 ) {
|
||||||
idle_state = 1000;
|
idle_state = 1000;
|
||||||
|
// Initialize the time offset (warp) after fgInitSubsystem
|
||||||
|
// (which initializes the lighting interpolation tables.)
|
||||||
|
fgInitTimeOffset();
|
||||||
|
|
||||||
// setup OpenGL view parameters
|
// setup OpenGL view parameters
|
||||||
globals->get_renderer()->init();
|
globals->get_renderer()->init();
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,8 @@ bool fgMainInit( int argc, char **argv );
|
||||||
|
|
||||||
|
|
||||||
extern int idle_state;
|
extern int idle_state;
|
||||||
|
extern long global_multi_loop;
|
||||||
|
extern double delta_time_sec;
|
||||||
|
|
||||||
extern char *homedir;
|
extern char *homedir;
|
||||||
extern char *hostname;
|
extern char *hostname;
|
||||||
|
|
|
@ -563,12 +563,16 @@ FGRenderer::init( void )
|
||||||
// Update all Visuals (redraws anything graphics related)
|
// Update all Visuals (redraws anything graphics related)
|
||||||
void
|
void
|
||||||
FGRenderer::update( bool refresh_camera_settings ) {
|
FGRenderer::update( bool refresh_camera_settings ) {
|
||||||
bool scenery_loaded = fgGetBool("sim/sceneryloaded", false)
|
bool scenery_loaded = fgGetBool("sim/sceneryloaded")
|
||||||
|| fgGetBool("sim/sceneryloaded-override");
|
|| fgGetBool("sim/sceneryloaded-override");
|
||||||
osgViewer::Viewer* viewer = globals->get_renderer()->getViewer();
|
osgViewer::Viewer* viewer = globals->get_renderer()->getViewer();
|
||||||
if (!scenery_loaded) {
|
if ( idle_state < 1000 || !scenery_loaded ) {
|
||||||
fgSetDouble("/sim/startup/splash-alpha", 1.0);
|
fgSetDouble("/sim/startup/splash-alpha", 1.0);
|
||||||
return;
|
|
||||||
|
// Keep resetting sim time while the sim is initializing
|
||||||
|
// the splash screen is now in the scenegraph
|
||||||
|
globals->set_sim_time_sec( 0.0 );
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fade out the splash screen over the first three seconds.
|
// Fade out the splash screen over the first three seconds.
|
||||||
|
@ -625,7 +629,9 @@ FGRenderer::update( bool refresh_camera_settings ) {
|
||||||
thesky->set_visibility(visibility_meters);
|
thesky->set_visibility(visibility_meters);
|
||||||
|
|
||||||
double altitude_m = fgGetDouble("/position/altitude-ft") * SG_FEET_TO_METER;
|
double altitude_m = fgGetDouble("/position/altitude-ft") * SG_FEET_TO_METER;
|
||||||
thesky->modify_vis( altitude_m, 0.0 /* time factor, now unused */);
|
thesky->modify_vis( altitude_m,
|
||||||
|
( global_multi_loop * fgGetInt("/sim/speed-up") )
|
||||||
|
/ (double)fgGetInt("/sim/model-hz") );
|
||||||
|
|
||||||
// update the sky dome
|
// update the sky dome
|
||||||
if ( skyblend ) {
|
if ( skyblend ) {
|
||||||
|
@ -667,8 +673,7 @@ FGRenderer::update( bool refresh_camera_settings ) {
|
||||||
scolor.cloud_color = SGVec3f(l->cloud_color().data());
|
scolor.cloud_color = SGVec3f(l->cloud_color().data());
|
||||||
scolor.sun_angle = l->get_sun_angle();
|
scolor.sun_angle = l->get_sun_angle();
|
||||||
scolor.moon_angle = l->get_moon_angle();
|
scolor.moon_angle = l->get_moon_angle();
|
||||||
|
|
||||||
double delta_time_sec = fgGetDouble("/sim/time/delta-sec");
|
|
||||||
thesky->reposition( sstate, *globals->get_ephem(), delta_time_sec );
|
thesky->reposition( sstate, *globals->get_ephem(), delta_time_sec );
|
||||||
thesky->repaint( scolor, *globals->get_ephem() );
|
thesky->repaint( scolor, *globals->get_ephem() );
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
#include <simgear/timing/sg_time.hxx>
|
#include <simgear/timing/sg_time.hxx>
|
||||||
|
|
||||||
#include <FDM/flightProperties.hxx>
|
#include <FDM/flightProperties.hxx>
|
||||||
|
#include <Time/tmp.hxx>
|
||||||
#include <Main/fg_props.hxx>
|
#include <Main/fg_props.hxx>
|
||||||
#include <Main/globals.hxx>
|
#include <Main/globals.hxx>
|
||||||
#include <Scenery/scenery.hxx>
|
#include <Scenery/scenery.hxx>
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
#include <simgear/io/iochannel.hxx>
|
#include <simgear/io/iochannel.hxx>
|
||||||
#include <simgear/timing/sg_time.hxx>
|
#include <simgear/timing/sg_time.hxx>
|
||||||
|
|
||||||
|
#include <Time/tmp.hxx>
|
||||||
#include <Main/fg_props.hxx>
|
#include <Main/fg_props.hxx>
|
||||||
#include <Main/globals.hxx>
|
#include <Main/globals.hxx>
|
||||||
#include <Scenery/scenery.hxx>
|
#include <Scenery/scenery.hxx>
|
||||||
|
|
|
@ -3,6 +3,6 @@ noinst_LIBRARIES = libTime.a
|
||||||
libTime_a_SOURCES = \
|
libTime_a_SOURCES = \
|
||||||
light.cxx light.hxx \
|
light.cxx light.hxx \
|
||||||
sunsolver.cxx sunsolver.hxx \
|
sunsolver.cxx sunsolver.hxx \
|
||||||
TimeManager.cxx TimeManager.hxx
|
tmp.cxx tmp.hxx
|
||||||
|
|
||||||
INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/src
|
INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/src
|
||||||
|
|
|
@ -1,359 +0,0 @@
|
||||||
// TimeManager.cxx -- simulation-wide time management
|
|
||||||
//
|
|
||||||
// Written by James Turner, started July 2010.
|
|
||||||
//
|
|
||||||
// Copyright (C) 2010 Curtis L. Olson - http://www.flightgear.org/~curt
|
|
||||||
//
|
|
||||||
// This program is free software; you can redistribute it and/or
|
|
||||||
// modify it under the terms of the GNU General Public License as
|
|
||||||
// published by the Free Software Foundation; either version 2 of the
|
|
||||||
// License, or (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful, but
|
|
||||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
# include "config.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "TimeManager.hxx"
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
# define WIN32_LEAN_AND_MEAN
|
|
||||||
# include <windows.h> // for Sleep()
|
|
||||||
#else
|
|
||||||
# include <unistd.h> // for usleep()
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <simgear/timing/sg_time.hxx>
|
|
||||||
#include <simgear/structure/event_mgr.hxx>
|
|
||||||
#include <simgear/misc/sg_path.hxx>
|
|
||||||
#include <simgear/timing/lowleveltime.h>
|
|
||||||
|
|
||||||
#include <Main/fg_props.hxx>
|
|
||||||
#include <Main/globals.hxx>
|
|
||||||
#include <Time/sunsolver.hxx>
|
|
||||||
|
|
||||||
TimeManager::TimeManager() :
|
|
||||||
_inited(false),
|
|
||||||
_impl(NULL)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void TimeManager::init()
|
|
||||||
{
|
|
||||||
if (_inited) {
|
|
||||||
// time manager has to be initialised early, so needs to be defensive
|
|
||||||
// about multiple initialisation
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_firstUpdate = true;
|
|
||||||
_inited = true;
|
|
||||||
_dtRemainder = 0.0;
|
|
||||||
|
|
||||||
_maxDtPerFrame = fgGetNode("/sim/max-simtime-per-frame", true);
|
|
||||||
_clockFreeze = fgGetNode("/sim/freeze/clock", true);
|
|
||||||
_timeOverride = fgGetNode("/sim/time/cur-time-override", true);
|
|
||||||
|
|
||||||
_longitudeDeg = fgGetNode("/position/longitude-deg", true);
|
|
||||||
_latitudeDeg = fgGetNode("/position/latitude-deg", true);
|
|
||||||
|
|
||||||
SGPath zone(globals->get_fg_root());
|
|
||||||
zone.append("Timezone");
|
|
||||||
double lon = _longitudeDeg->getDoubleValue() * SG_DEGREES_TO_RADIANS;
|
|
||||||
double lat = _latitudeDeg->getDoubleValue() * SG_DEGREES_TO_RADIANS;
|
|
||||||
_impl = new SGTime(lon, lat, zone.str(), _timeOverride->getLongValue());
|
|
||||||
|
|
||||||
globals->set_warp_delta(0);
|
|
||||||
|
|
||||||
globals->get_event_mgr()->addTask("updateLocalTime", this,
|
|
||||||
&TimeManager::updateLocalTime, 30*60 );
|
|
||||||
updateLocalTime();
|
|
||||||
|
|
||||||
_impl->update(lon, lat, _timeOverride->getLongValue(),
|
|
||||||
globals->get_warp());
|
|
||||||
globals->set_time_params(_impl);
|
|
||||||
|
|
||||||
initTimeOffset();
|
|
||||||
|
|
||||||
// frame/update-rate counters
|
|
||||||
_frameRate = fgGetNode("/sim/frame-rate", true);
|
|
||||||
_lastFrameTime = _impl->get_cur_time();
|
|
||||||
_frameCount = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void TimeManager::postinit()
|
|
||||||
{
|
|
||||||
initTimeOffset();
|
|
||||||
}
|
|
||||||
|
|
||||||
void TimeManager::reinit()
|
|
||||||
{
|
|
||||||
globals->set_time_params(NULL);
|
|
||||||
delete _impl;
|
|
||||||
_inited = false;
|
|
||||||
globals->get_event_mgr()->removeTask("updateLocalTime");
|
|
||||||
|
|
||||||
init();
|
|
||||||
postinit();
|
|
||||||
}
|
|
||||||
|
|
||||||
void TimeManager::computeTimeDeltas(double& simDt, double& realDt)
|
|
||||||
{
|
|
||||||
// Update the elapsed time.
|
|
||||||
if (_firstUpdate) {
|
|
||||||
_lastStamp.stamp();
|
|
||||||
_firstUpdate = false;
|
|
||||||
_lastClockFreeze = _clockFreeze->getBoolValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool scenery_loaded = fgGetBool("sim/sceneryloaded");
|
|
||||||
bool wait_for_scenery = !(scenery_loaded || fgGetBool("sim/sceneryloaded-override"));
|
|
||||||
|
|
||||||
if (!wait_for_scenery) {
|
|
||||||
throttleUpdateRate();
|
|
||||||
}
|
|
||||||
|
|
||||||
SGTimeStamp currentStamp;
|
|
||||||
currentStamp.stamp();
|
|
||||||
double dt = (currentStamp - _lastStamp).toSecs();
|
|
||||||
|
|
||||||
// Limit the time we need to spend in simulation loops
|
|
||||||
// That means, if the /sim/max-simtime-per-frame value is strictly positive
|
|
||||||
// you can limit the maximum amount of time you will do simulations for
|
|
||||||
// one frame to display. The cpu time spent in simulations code is roughly
|
|
||||||
// at least O(real_delta_time_sec). If this is (due to running debug
|
|
||||||
// builds or valgrind or something different blowing up execution times)
|
|
||||||
// larger than the real time you will no longer get any response
|
|
||||||
// from flightgear. This limits that effect. Just set to property from
|
|
||||||
// your .fgfsrc or commandline ...
|
|
||||||
double dtMax = _maxDtPerFrame->getDoubleValue();
|
|
||||||
if (0 < dtMax && dtMax < dt) {
|
|
||||||
dt = dtMax;
|
|
||||||
}
|
|
||||||
|
|
||||||
int model_hz = fgGetInt("/sim/model-hz");
|
|
||||||
|
|
||||||
SGSubsystemGroup* fdmGroup =
|
|
||||||
globals->get_subsystem_mgr()->get_group(SGSubsystemMgr::FDM);
|
|
||||||
fdmGroup->set_fixed_update_time(1.0 / model_hz);
|
|
||||||
|
|
||||||
// round the real time down to a multiple of 1/model-hz.
|
|
||||||
// this way all systems are updated the _same_ amount of dt.
|
|
||||||
dt += _dtRemainder;
|
|
||||||
int multiLoop = long(floor(dt * model_hz));
|
|
||||||
multiLoop = SGMisc<long>::max(0, multiLoop);
|
|
||||||
_dtRemainder = dt - double(multiLoop)/double(model_hz);
|
|
||||||
dt = double(multiLoop)/double(model_hz);
|
|
||||||
|
|
||||||
realDt = dt;
|
|
||||||
if (_clockFreeze->getBoolValue() || wait_for_scenery) {
|
|
||||||
simDt = 0;
|
|
||||||
} else {
|
|
||||||
simDt = dt;
|
|
||||||
}
|
|
||||||
|
|
||||||
_lastStamp = currentStamp;
|
|
||||||
globals->inc_sim_time_sec(simDt);
|
|
||||||
|
|
||||||
// These are useful, especially for Nasal scripts.
|
|
||||||
fgSetDouble("/sim/time/delta-realtime-sec", realDt);
|
|
||||||
fgSetDouble("/sim/time/delta-sec", simDt);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TimeManager::update(double dt)
|
|
||||||
{
|
|
||||||
bool freeze = _clockFreeze->getBoolValue();
|
|
||||||
if (freeze) {
|
|
||||||
// clock freeze requested
|
|
||||||
if (_timeOverride->getLongValue() == 0) {
|
|
||||||
fgSetLong( "/sim/time/cur-time-override", _impl->get_cur_time());
|
|
||||||
globals->set_warp(0);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// no clock freeze requested
|
|
||||||
if (_lastClockFreeze) {
|
|
||||||
// clock just unfroze, let's set warp as the difference
|
|
||||||
// between frozen time and current time so we don't get a
|
|
||||||
// time jump (and corresponding sky object and lighting
|
|
||||||
// jump.)
|
|
||||||
globals->set_warp(_timeOverride->getLongValue() - time(NULL));
|
|
||||||
fgSetLong( "/sim/time/cur-time-override", 0 );
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( globals->get_warp_delta() != 0 ) {
|
|
||||||
globals->inc_warp( globals->get_warp_delta() );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_lastClockFreeze = freeze;
|
|
||||||
double lon = _longitudeDeg->getDoubleValue() * SG_DEGREES_TO_RADIANS;
|
|
||||||
double lat = _latitudeDeg->getDoubleValue() * SG_DEGREES_TO_RADIANS;
|
|
||||||
_impl->update(lon, lat,
|
|
||||||
_timeOverride->getLongValue(),
|
|
||||||
globals->get_warp());
|
|
||||||
|
|
||||||
computeFrameRate();
|
|
||||||
}
|
|
||||||
|
|
||||||
void TimeManager::computeFrameRate()
|
|
||||||
{
|
|
||||||
// Calculate frame rate average
|
|
||||||
if ((_impl->get_cur_time() != _lastFrameTime) && (_lastFrameTime > 0)) {
|
|
||||||
_frameRate->setIntValue(_frameCount);
|
|
||||||
_frameCount = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
_lastFrameTime = _impl->get_cur_time();
|
|
||||||
++_frameCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
void TimeManager::throttleUpdateRate()
|
|
||||||
{
|
|
||||||
double throttle_hz = fgGetDouble("/sim/frame-rate-throttle-hz", 0.0);
|
|
||||||
SGTimeStamp currentStamp;
|
|
||||||
|
|
||||||
// common case, no throttle requested
|
|
||||||
if (throttle_hz <= 0.0) {
|
|
||||||
return; // no-op
|
|
||||||
}
|
|
||||||
|
|
||||||
double frame_us = 1000000.0 / throttle_hz;
|
|
||||||
#define FG_SLEEP_BASED_TIMING 1
|
|
||||||
#if defined(FG_SLEEP_BASED_TIMING)
|
|
||||||
// sleep based timing loop.
|
|
||||||
//
|
|
||||||
// Calling sleep, even usleep() on linux is less accurate than
|
|
||||||
// we like, but it does free up the cpu for other tasks during
|
|
||||||
// the sleep so it is desirable. Because of the way sleep()
|
|
||||||
// is implemented in consumer operating systems like windows
|
|
||||||
// and linux, you almost always sleep a little longer than the
|
|
||||||
// requested amount.
|
|
||||||
//
|
|
||||||
// To combat the problem of sleeping too long, we calculate the
|
|
||||||
// desired wait time and shorten it by 2000us (2ms) to avoid
|
|
||||||
// [hopefully] over-sleep'ing. The 2ms value was arrived at
|
|
||||||
// via experimentation. We follow this up at the end with a
|
|
||||||
// simple busy-wait loop to get the final pause timing exactly
|
|
||||||
// right.
|
|
||||||
//
|
|
||||||
// Assuming we don't oversleep by more than 2000us, this
|
|
||||||
// should be a reasonable compromise between sleep based
|
|
||||||
// waiting, and busy waiting.
|
|
||||||
|
|
||||||
// sleep() will always overshoot by a bit so undersleep by
|
|
||||||
// 2000us in the hopes of never oversleeping.
|
|
||||||
frame_us -= 2000.0;
|
|
||||||
if ( frame_us < 0.0 ) {
|
|
||||||
frame_us = 0.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
currentStamp.stamp();
|
|
||||||
|
|
||||||
double elapsed_us = (currentStamp - _lastStamp).toUSecs();
|
|
||||||
if ( elapsed_us < frame_us ) {
|
|
||||||
double requested_us = frame_us - elapsed_us;
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
Sleep ((int)(requested_us / 1000.0)) ;
|
|
||||||
#else
|
|
||||||
usleep(requested_us) ;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// busy wait timing loop.
|
|
||||||
//
|
|
||||||
// This yields the most accurate timing. If the previous
|
|
||||||
// ulMilliSecondSleep() call is omitted this will peg the cpu
|
|
||||||
// (which is just fine if FG is the only app you care about.)
|
|
||||||
currentStamp.stamp();
|
|
||||||
SGTimeStamp next_time_stamp = _lastStamp;
|
|
||||||
next_time_stamp += SGTimeStamp::fromSec(1e-6*frame_us);
|
|
||||||
while ( currentStamp < next_time_stamp ) {
|
|
||||||
currentStamp.stamp();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// periodic time updater wrapper
|
|
||||||
void TimeManager::updateLocalTime()
|
|
||||||
{
|
|
||||||
SGPath zone(globals->get_fg_root());
|
|
||||||
zone.append("Timezone");
|
|
||||||
|
|
||||||
double lon = _longitudeDeg->getDoubleValue() * SG_DEGREES_TO_RADIANS;
|
|
||||||
double lat = _latitudeDeg->getDoubleValue() * SG_DEGREES_TO_RADIANS;
|
|
||||||
|
|
||||||
SG_LOG(SG_GENERAL, SG_INFO, "updateLocal(" << lon << ", " << lat << ", " << zone.str() << ")");
|
|
||||||
_impl->updateLocal(lon, lat, zone.str());
|
|
||||||
}
|
|
||||||
|
|
||||||
void TimeManager::initTimeOffset()
|
|
||||||
{
|
|
||||||
// Handle potential user specified time offsets
|
|
||||||
int orig_warp = globals->get_warp();
|
|
||||||
time_t cur_time = _impl->get_cur_time();
|
|
||||||
time_t currGMT = sgTimeGetGMT( gmtime(&cur_time) );
|
|
||||||
time_t systemLocalTime = sgTimeGetGMT( localtime(&cur_time) );
|
|
||||||
time_t aircraftLocalTime =
|
|
||||||
sgTimeGetGMT( fgLocaltime(&cur_time, _impl->get_zonename() ) );
|
|
||||||
|
|
||||||
// Okay, we now have several possible scenarios
|
|
||||||
int offset = fgGetInt("/sim/startup/time-offset");
|
|
||||||
string offset_type = fgGetString("/sim/startup/time-offset-type");
|
|
||||||
double lon = _longitudeDeg->getDoubleValue() * SG_DEGREES_TO_RADIANS;
|
|
||||||
double lat = _latitudeDeg->getDoubleValue() * SG_DEGREES_TO_RADIANS;
|
|
||||||
int warp = 0;
|
|
||||||
|
|
||||||
if ( offset_type == "real" ) {
|
|
||||||
warp = 0;
|
|
||||||
} else if ( offset_type == "dawn" ) {
|
|
||||||
warp = fgTimeSecondsUntilSunAngle( cur_time, lon, lat, 90.0, true );
|
|
||||||
} else if ( offset_type == "morning" ) {
|
|
||||||
warp = fgTimeSecondsUntilSunAngle( cur_time, lon, lat, 75.0, true );
|
|
||||||
} else if ( offset_type == "noon" ) {
|
|
||||||
warp = fgTimeSecondsUntilSunAngle( cur_time, lon, lat, 0.0, true );
|
|
||||||
} else if ( offset_type == "afternoon" ) {
|
|
||||||
warp = fgTimeSecondsUntilSunAngle( cur_time, lon, lat, 60.0, false );
|
|
||||||
} else if ( offset_type == "dusk" ) {
|
|
||||||
warp = fgTimeSecondsUntilSunAngle( cur_time, lon, lat, 90.0, false );
|
|
||||||
} else if ( offset_type == "evening" ) {
|
|
||||||
warp = fgTimeSecondsUntilSunAngle( cur_time, lon, lat, 100.0, false );
|
|
||||||
} else if ( offset_type == "midnight" ) {
|
|
||||||
warp = fgTimeSecondsUntilSunAngle( cur_time, lon, lat, 180.0, false );
|
|
||||||
} else if ( offset_type == "system-offset" ) {
|
|
||||||
warp = offset;
|
|
||||||
orig_warp = 0;
|
|
||||||
} else if ( offset_type == "gmt-offset" ) {
|
|
||||||
warp = offset - (currGMT - systemLocalTime);
|
|
||||||
orig_warp = 0;
|
|
||||||
} else if ( offset_type == "latitude-offset" ) {
|
|
||||||
warp = offset - (aircraftLocalTime - systemLocalTime);
|
|
||||||
orig_warp = 0;
|
|
||||||
} else if ( offset_type == "system" ) {
|
|
||||||
warp = offset - (systemLocalTime - currGMT) - cur_time;
|
|
||||||
} else if ( offset_type == "gmt" ) {
|
|
||||||
warp = offset - cur_time;
|
|
||||||
} else if ( offset_type == "latitude" ) {
|
|
||||||
warp = offset - (aircraftLocalTime - currGMT)- cur_time;
|
|
||||||
} else {
|
|
||||||
SG_LOG( SG_GENERAL, SG_ALERT,
|
|
||||||
"TimeManager::initTimeOffset: unsupported offset: " << offset_type );
|
|
||||||
warp = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
globals->set_warp( orig_warp + warp );
|
|
||||||
_impl->update(lon, lat, _timeOverride->getLongValue(),
|
|
||||||
globals->get_warp() );
|
|
||||||
|
|
||||||
SG_LOG( SG_GENERAL, SG_INFO, "After fgInitTimeOffset(): warp = "
|
|
||||||
<< globals->get_warp() );
|
|
||||||
}
|
|
|
@ -1,78 +0,0 @@
|
||||||
// TimeManager.hxx -- simulation-wide time management
|
|
||||||
//
|
|
||||||
// Written by James Turner, started July 2010.
|
|
||||||
//
|
|
||||||
// Copyright (C) 2010 Curtis L. Olson - http://www.flightgear.org/~curt
|
|
||||||
//
|
|
||||||
// This program is free software; you can redistribute it and/or
|
|
||||||
// modify it under the terms of the GNU General Public License as
|
|
||||||
// published by the Free Software Foundation; either version 2 of the
|
|
||||||
// License, or (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful, but
|
|
||||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
||||||
|
|
||||||
#ifndef FG_TIME_TIMEMANAGER_HXX
|
|
||||||
#define FG_TIME_TIMEMANAGER_HXX
|
|
||||||
|
|
||||||
#include <simgear/structure/subsystem_mgr.hxx>
|
|
||||||
|
|
||||||
// forward decls
|
|
||||||
class SGTime;
|
|
||||||
|
|
||||||
class TimeManager : public SGSubsystem
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
TimeManager();
|
|
||||||
|
|
||||||
void computeTimeDeltas(double& simDt, double& realDt);
|
|
||||||
|
|
||||||
virtual void init();
|
|
||||||
virtual void reinit();
|
|
||||||
virtual void postinit();
|
|
||||||
|
|
||||||
void update(double dt);
|
|
||||||
|
|
||||||
private:
|
|
||||||
/**
|
|
||||||
* Ensure a consistent update-rate using a combination of
|
|
||||||
* sleep()-ing and busy-waiting.
|
|
||||||
*/
|
|
||||||
void throttleUpdateRate();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Compute frame (update) rate and write it to a property
|
|
||||||
*/
|
|
||||||
void computeFrameRate();
|
|
||||||
|
|
||||||
void updateLocalTime();
|
|
||||||
|
|
||||||
// set up a time offset (aka warp) if one is specified
|
|
||||||
void initTimeOffset();
|
|
||||||
|
|
||||||
bool _inited;
|
|
||||||
SGTime* _impl;
|
|
||||||
SGTimeStamp _lastStamp;
|
|
||||||
bool _firstUpdate;
|
|
||||||
double _dtRemainder;
|
|
||||||
SGPropertyNode_ptr _maxDtPerFrame;
|
|
||||||
SGPropertyNode_ptr _clockFreeze;
|
|
||||||
SGPropertyNode_ptr _timeOverride;
|
|
||||||
bool _lastClockFreeze;
|
|
||||||
|
|
||||||
SGPropertyNode_ptr _longitudeDeg;
|
|
||||||
SGPropertyNode_ptr _latitudeDeg;
|
|
||||||
|
|
||||||
// frame-rate / update-rate counters
|
|
||||||
SGPropertyNode_ptr _frameRate;
|
|
||||||
time_t _lastFrameTime;
|
|
||||||
int _frameCount;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // of FG_TIME_TIMEMANAGER_HXX
|
|
|
@ -36,8 +36,6 @@
|
||||||
#include <simgear/misc/sg_path.hxx>
|
#include <simgear/misc/sg_path.hxx>
|
||||||
#include <simgear/scene/sky/sky.hxx>
|
#include <simgear/scene/sky/sky.hxx>
|
||||||
#include <simgear/screen/colors.hxx>
|
#include <simgear/screen/colors.hxx>
|
||||||
#include <simgear/timing/sg_time.hxx>
|
|
||||||
#include <simgear/structure/event_mgr.hxx>
|
|
||||||
|
|
||||||
#include <Main/main.hxx>
|
#include <Main/main.hxx>
|
||||||
#include <Main/globals.hxx>
|
#include <Main/globals.hxx>
|
||||||
|
@ -46,38 +44,7 @@
|
||||||
#include <Main/viewer.hxx>
|
#include <Main/viewer.hxx>
|
||||||
|
|
||||||
#include "light.hxx"
|
#include "light.hxx"
|
||||||
#include "sunsolver.hxx"
|
#include "tmp.hxx"
|
||||||
|
|
||||||
/**
|
|
||||||
* Map i.e. project a vector onto a plane.
|
|
||||||
* @param normal (in) normal vector for the plane
|
|
||||||
* @param v0 (in) a point on the plane
|
|
||||||
* @param vec (in) the vector to map onto the plane
|
|
||||||
*/
|
|
||||||
static SGVec3f map_vec_onto_cur_surface_plane(const SGVec3f& normal,
|
|
||||||
const SGVec3f& v0,
|
|
||||||
const SGVec3f& vec)
|
|
||||||
{
|
|
||||||
// calculate a vector "u1" representing the shortest distance from
|
|
||||||
// the plane specified by normal and v0 to a point specified by
|
|
||||||
// "vec". "u1" represents both the direction and magnitude of
|
|
||||||
// this desired distance.
|
|
||||||
|
|
||||||
// u1 = ( (normal <dot> vec) / (normal <dot> normal) ) * normal
|
|
||||||
SGVec3f u1 = (dot(normal, vec) / dot(normal, normal)) * normal;
|
|
||||||
|
|
||||||
// calculate the vector "v" which is the vector "vec" mapped onto
|
|
||||||
// the plane specified by "normal" and "v0".
|
|
||||||
|
|
||||||
// v = v0 + vec - u1
|
|
||||||
SGVec3f v = v0 + vec - u1;
|
|
||||||
|
|
||||||
// Calculate the vector "result" which is "v" - "v0" which is a
|
|
||||||
// directional vector pointing from v0 towards v
|
|
||||||
|
|
||||||
// result = v - v0
|
|
||||||
return v - v0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Constructor
|
// Constructor
|
||||||
|
@ -147,9 +114,6 @@ void FGLight::init () {
|
||||||
SGPath sky_path = path;
|
SGPath sky_path = path;
|
||||||
sky_path.append( "Lighting/sky" );
|
sky_path.append( "Lighting/sky" );
|
||||||
_sky_tbl = new SGInterpTable( sky_path.str() );
|
_sky_tbl = new SGInterpTable( sky_path.str() );
|
||||||
|
|
||||||
globals->get_event_mgr()->addTask("updateSunPos", this,
|
|
||||||
&FGLight::updateSunPos, 0.5 );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -164,7 +128,8 @@ void FGLight::reinit () {
|
||||||
|
|
||||||
init();
|
init();
|
||||||
|
|
||||||
updateSunPos();
|
fgUpdateSunPos();
|
||||||
|
|
||||||
update_sky_color();
|
update_sky_color();
|
||||||
update_adj_fog_color();
|
update_adj_fog_color();
|
||||||
}
|
}
|
||||||
|
@ -223,12 +188,18 @@ void FGLight::unbind () {
|
||||||
|
|
||||||
|
|
||||||
// update lighting parameters based on current sun position
|
// update lighting parameters based on current sun position
|
||||||
void FGLight::update( double dt )
|
void FGLight::update( double dt ) {
|
||||||
{
|
|
||||||
|
_dt_total += dt;
|
||||||
|
if (_dt_total >= 0.5) {
|
||||||
|
_dt_total -= 0.5;
|
||||||
|
fgUpdateSunPos();
|
||||||
|
}
|
||||||
|
|
||||||
update_adj_fog_color();
|
update_adj_fog_color();
|
||||||
|
|
||||||
if (_prev_sun_angle != _sun_angle) {
|
if (_prev_sun_angle != _sun_angle) {
|
||||||
_prev_sun_angle = _sun_angle;
|
_prev_sun_angle = _sun_angle;
|
||||||
update_sky_color();
|
update_sky_color();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -411,101 +382,3 @@ void FGLight::update_adj_fog_color () {
|
||||||
gamma_correct_rgb( _sky_color.data(), gamma );
|
gamma_correct_rgb( _sky_color.data(), gamma );
|
||||||
}
|
}
|
||||||
|
|
||||||
// update the cur_time_params structure with the current sun position
|
|
||||||
void FGLight::updateSunPos()
|
|
||||||
{
|
|
||||||
SGTime *t = globals->get_time_params();
|
|
||||||
FGViewer *v = globals->get_current_view();
|
|
||||||
|
|
||||||
SG_LOG( SG_EVENT, SG_DEBUG, " Updating Sun position" );
|
|
||||||
SG_LOG( SG_EVENT, SG_DEBUG, " Gst = " << t->getGst() );
|
|
||||||
|
|
||||||
double sun_l;
|
|
||||||
double sun_gd_lat;
|
|
||||||
fgSunPositionGST(t->getGst(), &sun_l, &sun_gd_lat);
|
|
||||||
set_sun_lon(sun_l);
|
|
||||||
set_sun_lat(sun_gd_lat);
|
|
||||||
SGVec3d sunpos(SGVec3d::fromGeod(SGGeod::fromRad(sun_l, sun_gd_lat)));
|
|
||||||
|
|
||||||
SG_LOG( SG_EVENT, SG_DEBUG, " t->cur_time = " << t->get_cur_time() );
|
|
||||||
SG_LOG( SG_EVENT, SG_DEBUG,
|
|
||||||
" Sun Geodetic lat = " << sun_gd_lat
|
|
||||||
<< " Geodetic lat = " << sun_gd_lat );
|
|
||||||
|
|
||||||
// update the sun light vector
|
|
||||||
sun_vec() = SGVec4f(toVec3f(normalize(sunpos)), 0);
|
|
||||||
sun_vec_inv() = - sun_vec();
|
|
||||||
|
|
||||||
// calculate the sun's relative angle to local up
|
|
||||||
SGVec3d viewPos = v->get_view_pos();
|
|
||||||
SGQuatd hlOr = SGQuatd::fromLonLat(SGGeod::fromCart(viewPos));
|
|
||||||
SGVec3f world_up = toVec3f(hlOr.backTransform(-SGVec3d::e3()));
|
|
||||||
SGVec3f nsun = toVec3f(normalize(sunpos));
|
|
||||||
// cout << "nup = " << nup[0] << "," << nup[1] << ","
|
|
||||||
// << nup[2] << endl;
|
|
||||||
// cout << "nsun = " << nsun[0] << "," << nsun[1] << ","
|
|
||||||
// << nsun[2] << endl;
|
|
||||||
|
|
||||||
set_sun_angle( acos( dot ( world_up, nsun ) ) );
|
|
||||||
SG_LOG( SG_EVENT, SG_DEBUG, "sun angle relative to current location = "
|
|
||||||
<< get_sun_angle() );
|
|
||||||
|
|
||||||
// calculate vector to sun's position on the earth's surface
|
|
||||||
SGVec3d rel_sunpos = sunpos - v->get_view_pos();
|
|
||||||
// vector in cartesian coordinates from current position to the
|
|
||||||
// postion on the earth's surface the sun is directly over
|
|
||||||
SGVec3f to_sun = toVec3f(rel_sunpos);
|
|
||||||
// printf( "Vector to sun = %.2f %.2f %.2f\n",
|
|
||||||
// v->to_sun[0], v->to_sun[1], v->to_sun[2]);
|
|
||||||
|
|
||||||
// Given a vector from the view position to the point on the
|
|
||||||
// earth's surface the sun is directly over, map into onto the
|
|
||||||
// local plane representing "horizontal".
|
|
||||||
|
|
||||||
// surface direction to go to head towards sun
|
|
||||||
SGVec3f surface_to_sun;
|
|
||||||
SGVec3f view_pos = toVec3f(v->get_view_pos());
|
|
||||||
surface_to_sun = map_vec_onto_cur_surface_plane(world_up, view_pos, to_sun);
|
|
||||||
surface_to_sun = normalize(surface_to_sun);
|
|
||||||
// cout << "(sg) Surface direction to sun is "
|
|
||||||
// << surface_to_sun[0] << ","
|
|
||||||
// << surface_to_sun[1] << ","
|
|
||||||
// << surface_to_sun[2] << endl;
|
|
||||||
// cout << "Should be close to zero = "
|
|
||||||
// << sgScalarProductVec3(nup, surface_to_sun) << endl;
|
|
||||||
|
|
||||||
// calculate the angle between surface_to_sun and
|
|
||||||
// v->get_surface_east(). We do this so we can sort out the
|
|
||||||
// acos() ambiguity. I wish I could think of a more efficient
|
|
||||||
// way. :-(
|
|
||||||
SGVec3f surface_east(toVec3f(hlOr.backTransform(SGVec3d::e2())));
|
|
||||||
float east_dot = dot( surface_to_sun, surface_east );
|
|
||||||
// cout << " East dot product = " << east_dot << endl;
|
|
||||||
|
|
||||||
// calculate the angle between v->surface_to_sun and
|
|
||||||
// v->surface_south. this is how much we have to rotate the sky
|
|
||||||
// for it to align with the sun
|
|
||||||
SGVec3f surface_south(toVec3f(hlOr.backTransform(-SGVec3d::e1())));
|
|
||||||
float dot_ = dot( surface_to_sun, surface_south );
|
|
||||||
// cout << " Dot product = " << dot << endl;
|
|
||||||
|
|
||||||
if (dot_ > 1.0) {
|
|
||||||
SG_LOG( SG_ASTRO, SG_INFO,
|
|
||||||
"Dot product = " << dot_ << " is greater than 1.0" );
|
|
||||||
dot_ = 1.0;
|
|
||||||
}
|
|
||||||
else if (dot_ < -1.0) {
|
|
||||||
SG_LOG( SG_ASTRO, SG_INFO,
|
|
||||||
"Dot product = " << dot_ << " is less than -1.0" );
|
|
||||||
dot_ = -1.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( east_dot >= 0 ) {
|
|
||||||
set_sun_rotation( acos(dot_) );
|
|
||||||
} else {
|
|
||||||
set_sun_rotation( -acos(dot_) );
|
|
||||||
}
|
|
||||||
// cout << " Sky needs to rotate = " << angle << " rads = "
|
|
||||||
// << angle * SGD_RADIANS_TO_DEGREES << " degrees." << endl;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
@ -102,8 +102,6 @@ private:
|
||||||
void update_sky_color ();
|
void update_sky_color ();
|
||||||
void update_adj_fog_color ();
|
void update_adj_fog_color ();
|
||||||
|
|
||||||
void updateSunPos();
|
|
||||||
|
|
||||||
// properties for chrome light; not a tie because I want to fire
|
// properties for chrome light; not a tie because I want to fire
|
||||||
// property listeners when the values change.
|
// property listeners when the values change.
|
||||||
SGPropertyNode_ptr _chromeProps[4];
|
SGPropertyNode_ptr _chromeProps[4];
|
||||||
|
|
|
@ -37,6 +37,7 @@
|
||||||
#include <Main/globals.hxx>
|
#include <Main/globals.hxx>
|
||||||
#include <Main/fg_props.hxx>
|
#include <Main/fg_props.hxx>
|
||||||
|
|
||||||
|
#include "tmp.hxx"
|
||||||
#include "sunsolver.hxx"
|
#include "sunsolver.hxx"
|
||||||
|
|
||||||
|
|
||||||
|
|
238
src/Time/tmp.cxx
Normal file
238
src/Time/tmp.cxx
Normal file
|
@ -0,0 +1,238 @@
|
||||||
|
// tmp.cxx -- stuff I don't know what to do with at the moment
|
||||||
|
//
|
||||||
|
// Written by Curtis Olson, started July 2000.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2000 Curtis L. Olson - http://www.flightgear.org/~curt
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU General Public License as
|
||||||
|
// published by the Free Software Foundation; either version 2 of the
|
||||||
|
// License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful, but
|
||||||
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
//
|
||||||
|
// $Id$
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
# include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <simgear/math/SGMath.hxx>
|
||||||
|
#include <simgear/misc/sg_path.hxx>
|
||||||
|
#include <simgear/timing/sg_time.hxx>
|
||||||
|
|
||||||
|
#include <Main/fg_props.hxx>
|
||||||
|
#include <Main/globals.hxx>
|
||||||
|
#include <Main/viewer.hxx>
|
||||||
|
#include <Scenery/scenery.hxx>
|
||||||
|
|
||||||
|
#include "light.hxx"
|
||||||
|
#include "sunsolver.hxx"
|
||||||
|
#include "tmp.hxx"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map i.e. project a vector onto a plane.
|
||||||
|
* @param normal (in) normal vector for the plane
|
||||||
|
* @param v0 (in) a point on the plane
|
||||||
|
* @param vec (in) the vector to map onto the plane
|
||||||
|
*/
|
||||||
|
static SGVec3f map_vec_onto_cur_surface_plane(const SGVec3f& normal,
|
||||||
|
const SGVec3f& v0,
|
||||||
|
const SGVec3f& vec)
|
||||||
|
{
|
||||||
|
// calculate a vector "u1" representing the shortest distance from
|
||||||
|
// the plane specified by normal and v0 to a point specified by
|
||||||
|
// "vec". "u1" represents both the direction and magnitude of
|
||||||
|
// this desired distance.
|
||||||
|
|
||||||
|
// u1 = ( (normal <dot> vec) / (normal <dot> normal) ) * normal
|
||||||
|
SGVec3f u1 = (dot(normal, vec) / dot(normal, normal)) * normal;
|
||||||
|
|
||||||
|
// calculate the vector "v" which is the vector "vec" mapped onto
|
||||||
|
// the plane specified by "normal" and "v0".
|
||||||
|
|
||||||
|
// v = v0 + vec - u1
|
||||||
|
SGVec3f v = v0 + vec - u1;
|
||||||
|
|
||||||
|
// Calculate the vector "result" which is "v" - "v0" which is a
|
||||||
|
// directional vector pointing from v0 towards v
|
||||||
|
|
||||||
|
// result = v - v0
|
||||||
|
return v - v0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// periodic time updater wrapper
|
||||||
|
void fgUpdateLocalTime() {
|
||||||
|
static const SGPropertyNode *longitude
|
||||||
|
= fgGetNode("/position/longitude-deg");
|
||||||
|
static const SGPropertyNode *latitude
|
||||||
|
= fgGetNode("/position/latitude-deg");
|
||||||
|
|
||||||
|
SGPath zone( globals->get_fg_root() );
|
||||||
|
zone.append( "Timezone" );
|
||||||
|
|
||||||
|
SG_LOG(SG_GENERAL, SG_INFO, "updateLocal("
|
||||||
|
<< longitude->getDoubleValue() * SGD_DEGREES_TO_RADIANS
|
||||||
|
<< ", "
|
||||||
|
<< latitude->getDoubleValue() * SGD_DEGREES_TO_RADIANS
|
||||||
|
<< ", " << zone.str() << ")");
|
||||||
|
globals->get_time_params()->updateLocal( longitude->getDoubleValue()
|
||||||
|
* SGD_DEGREES_TO_RADIANS,
|
||||||
|
latitude->getDoubleValue()
|
||||||
|
* SGD_DEGREES_TO_RADIANS,
|
||||||
|
zone.str() );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// update the cur_time_params structure with the current sun position
|
||||||
|
void fgUpdateSunPos( void ) {
|
||||||
|
#if 0
|
||||||
|
// This only works at lat,lon = 0,0
|
||||||
|
// need to find a way to get it working at other locations
|
||||||
|
|
||||||
|
FGLight *light = (FGLight *)(globals->get_subsystem("lighting"));
|
||||||
|
FGViewer *viewer = globals->get_current_view();
|
||||||
|
SGTime *time_now = globals->get_time_params();
|
||||||
|
|
||||||
|
SG_LOG( SG_EVENT, SG_DEBUG, " Updating Sun position" );
|
||||||
|
SG_LOG( SG_EVENT, SG_DEBUG, " Gst = " << time_now->getGst() );
|
||||||
|
|
||||||
|
double sun_lon, sun_lat;
|
||||||
|
fgSunPositionGST(time_now->getGst(), &sun_lon, &sun_lat);
|
||||||
|
light->set_sun_lon(sun_lon);
|
||||||
|
light->set_sun_lat(sun_lat);
|
||||||
|
|
||||||
|
// update the sun light vector
|
||||||
|
// calculations are in the horizontal normal plane: x-north, y-east, z-down
|
||||||
|
static SGQuatd q = SGQuatd::fromLonLat(SGGeod::fromRad(0,0));
|
||||||
|
|
||||||
|
// sun orientation
|
||||||
|
SGGeod geodSunPos = SGGeod::fromRad(sun_lon, sun_lat);
|
||||||
|
SGQuatd sunOr = SGQuatd::fromLonLat(geodSunPos);
|
||||||
|
|
||||||
|
// scenery orientation
|
||||||
|
SGGeod geodViewPos = SGGeod::fromCart(viewer->getViewPosition());
|
||||||
|
SGQuatd hlOr = SGQuatd::fromLonLat(geodViewPos);
|
||||||
|
SGVec3d localAt = hlOr.backTransform(SGVec3d::e3());
|
||||||
|
|
||||||
|
// transpose the sun direction from (lat,lon) to (0,0)
|
||||||
|
SGVec3d transSunDir = (q*sunOr).transform(-localAt);
|
||||||
|
SGQuatd sunDirOr = SGQuatd::fromRealImag(0, transSunDir);
|
||||||
|
|
||||||
|
// transpose the calculated sun vector back to (lat,lon)
|
||||||
|
SGVec3d sunDirection = sunDirOr.transform(localAt);
|
||||||
|
light->set_sun_rotation( acos(sunDirection[1])-SGD_PI_2 );
|
||||||
|
light->set_sun_angle( acos(-sunDirection[2]) );
|
||||||
|
|
||||||
|
SGVec3d sunPos = SGVec3d::fromGeod(geodSunPos);
|
||||||
|
light->sun_vec() = SGVec4f(toVec3f(normalize(sunPos)), 0);
|
||||||
|
light->sun_vec_inv() = -light->sun_vec();
|
||||||
|
|
||||||
|
#else
|
||||||
|
FGLight *l = (FGLight *)(globals->get_subsystem("lighting"));
|
||||||
|
SGTime *t = globals->get_time_params();
|
||||||
|
FGViewer *v = globals->get_current_view();
|
||||||
|
|
||||||
|
SG_LOG( SG_EVENT, SG_DEBUG, " Updating Sun position" );
|
||||||
|
SG_LOG( SG_EVENT, SG_DEBUG, " Gst = " << t->getGst() );
|
||||||
|
|
||||||
|
double sun_l;
|
||||||
|
double sun_gd_lat;
|
||||||
|
fgSunPositionGST(t->getGst(), &sun_l, &sun_gd_lat);
|
||||||
|
l->set_sun_lon(sun_l);
|
||||||
|
l->set_sun_lat(sun_gd_lat);
|
||||||
|
SGVec3d sunpos(SGVec3d::fromGeod(SGGeod::fromRad(sun_l, sun_gd_lat)));
|
||||||
|
|
||||||
|
SG_LOG( SG_EVENT, SG_DEBUG, " t->cur_time = " << t->get_cur_time() );
|
||||||
|
SG_LOG( SG_EVENT, SG_DEBUG,
|
||||||
|
" Sun Geodetic lat = " << sun_gd_lat
|
||||||
|
<< " Geodetic lat = " << sun_gd_lat );
|
||||||
|
|
||||||
|
// update the sun light vector
|
||||||
|
l->sun_vec() = SGVec4f(toVec3f(normalize(sunpos)), 0);
|
||||||
|
l->sun_vec_inv() = - l->sun_vec();
|
||||||
|
|
||||||
|
// calculate the sun's relative angle to local up
|
||||||
|
SGVec3d viewPos = v->get_view_pos();
|
||||||
|
SGQuatd hlOr = SGQuatd::fromLonLat(SGGeod::fromCart(viewPos));
|
||||||
|
SGVec3f world_up = toVec3f(hlOr.backTransform(-SGVec3d::e3()));
|
||||||
|
SGVec3f nsun = toVec3f(normalize(sunpos));
|
||||||
|
// cout << "nup = " << nup[0] << "," << nup[1] << ","
|
||||||
|
// << nup[2] << endl;
|
||||||
|
// cout << "nsun = " << nsun[0] << "," << nsun[1] << ","
|
||||||
|
// << nsun[2] << endl;
|
||||||
|
|
||||||
|
l->set_sun_angle( acos( dot ( world_up, nsun ) ) );
|
||||||
|
SG_LOG( SG_EVENT, SG_DEBUG, "sun angle relative to current location = "
|
||||||
|
<< l->get_sun_angle() );
|
||||||
|
|
||||||
|
// calculate vector to sun's position on the earth's surface
|
||||||
|
SGVec3d rel_sunpos = sunpos - v->get_view_pos();
|
||||||
|
// vector in cartesian coordinates from current position to the
|
||||||
|
// postion on the earth's surface the sun is directly over
|
||||||
|
SGVec3f to_sun = toVec3f(rel_sunpos);
|
||||||
|
// printf( "Vector to sun = %.2f %.2f %.2f\n",
|
||||||
|
// v->to_sun[0], v->to_sun[1], v->to_sun[2]);
|
||||||
|
|
||||||
|
// Given a vector from the view position to the point on the
|
||||||
|
// earth's surface the sun is directly over, map into onto the
|
||||||
|
// local plane representing "horizontal".
|
||||||
|
|
||||||
|
// surface direction to go to head towards sun
|
||||||
|
SGVec3f view_pos = toVec3f(v->get_view_pos());
|
||||||
|
SGVec3f surface_to_sun = map_vec_onto_cur_surface_plane(world_up, view_pos, to_sun);
|
||||||
|
|
||||||
|
surface_to_sun = normalize(surface_to_sun);
|
||||||
|
// cout << "(sg) Surface direction to sun is "
|
||||||
|
// << surface_to_sun[0] << ","
|
||||||
|
// << surface_to_sun[1] << ","
|
||||||
|
// << surface_to_sun[2] << endl;
|
||||||
|
// cout << "Should be close to zero = "
|
||||||
|
// << sgScalarProductVec3(nup, surface_to_sun) << endl;
|
||||||
|
|
||||||
|
// calculate the angle between surface_to_sun and
|
||||||
|
// v->get_surface_east(). We do this so we can sort out the
|
||||||
|
// acos() ambiguity. I wish I could think of a more efficient
|
||||||
|
// way. :-(
|
||||||
|
SGVec3f surface_east(toVec3f(hlOr.backTransform(SGVec3d::e2())));
|
||||||
|
float east_dot = dot( surface_to_sun, surface_east );
|
||||||
|
// cout << " East dot product = " << east_dot << endl;
|
||||||
|
|
||||||
|
// calculate the angle between v->surface_to_sun and
|
||||||
|
// v->surface_south. this is how much we have to rotate the sky
|
||||||
|
// for it to align with the sun
|
||||||
|
SGVec3f surface_south(toVec3f(hlOr.backTransform(-SGVec3d::e1())));
|
||||||
|
float dot_ = dot( surface_to_sun, surface_south );
|
||||||
|
// cout << " Dot product = " << dot << endl;
|
||||||
|
|
||||||
|
if (dot_ > 1.0) {
|
||||||
|
SG_LOG( SG_ASTRO, SG_INFO,
|
||||||
|
"Dot product = " << dot_ << " is greater than 1.0" );
|
||||||
|
dot_ = 1.0;
|
||||||
|
}
|
||||||
|
else if (dot_ < -1.0) {
|
||||||
|
SG_LOG( SG_ASTRO, SG_INFO,
|
||||||
|
"Dot product = " << dot_ << " is less than -1.0" );
|
||||||
|
dot_ = -1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( east_dot >= 0 ) {
|
||||||
|
l->set_sun_rotation( acos(dot_) );
|
||||||
|
} else {
|
||||||
|
l->set_sun_rotation( -acos(dot_) );
|
||||||
|
}
|
||||||
|
// cout << " Sky needs to rotate = " << angle << " rads = "
|
||||||
|
// << angle * SGD_RADIANS_TO_DEGREES << " degrees." << endl;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
45
src/Time/tmp.hxx
Normal file
45
src/Time/tmp.hxx
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
// tmp.hxx -- stuff I don't know what to do with at the moment
|
||||||
|
//
|
||||||
|
// Written by Curtis Olson, started July 2000.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2000 Curtis L. Olson - http://www.flightgear.org/~curt
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU General Public License as
|
||||||
|
// published by the Free Software Foundation; either version 2 of the
|
||||||
|
// License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful, but
|
||||||
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
//
|
||||||
|
// $Id$
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef _TMP_HXX
|
||||||
|
#define _TMP_HXX
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef __cplusplus
|
||||||
|
# error This library requires C++
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
# include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// periodic time updater
|
||||||
|
void fgUpdateLocalTime();
|
||||||
|
|
||||||
|
// update the cur_time_params structure with the current sun position
|
||||||
|
void fgUpdateSunPos( void );
|
||||||
|
|
||||||
|
#endif // _LIGHT_HXX
|
||||||
|
|
Loading…
Reference in a new issue