1
0
Fork 0

Create TimeManager subsystem, and collect the time related code out of main.cxx and fg_init.cxx into it.

Remove the unfortunately named 'tmp.[cxx|hxx]', pushing the remaining code in FGLight.
This commit is contained in:
James Turner 2010-07-13 21:50:44 +01:00
parent 7aba4333a2
commit 50eb95dcad
17 changed files with 616 additions and 697 deletions

View file

@ -4512,11 +4512,11 @@
>
</File>
<File
RelativePath="..\..\..\src\Time\tmp.cxx"
RelativePath="..\..\..\src\Time\TimeManager.cxx"
>
</File>
<File
RelativePath="..\..\..\src\Time\tmp.hxx"
RelativePath="..\..\..\src\Time\TimeManager.hxx"
>
</File>
</Filter>

View file

@ -37,7 +37,6 @@
#include <Scripting/NasalSys.hxx>
#include <Sound/sample_queue.hxx>
#include <Time/sunsolver.hxx>
#include <Time/tmp.hxx>
#include "fg_init.hxx"
#include "fg_io.hxx"

View file

@ -62,8 +62,6 @@
#include <simgear/scene/material/matlib.hxx>
#include <simgear/scene/model/particles.hxx>
#include <simgear/sound/soundmgr_openal.hxx>
#include <simgear/timing/sg_time.hxx>
#include <simgear/timing/lowleveltime.h>
#include <Aircraft/controls.hxx>
#include <Aircraft/replay.hxx>
@ -107,8 +105,6 @@
#include <Sound/voice.hxx>
#include <Systems/system_mgr.hxx>
#include <Time/light.hxx>
#include <Time/sunsolver.hxx>
#include <Time/tmp.hxx>
#include <Traffic/TrafficMgr.hxx>
#include <MultiPlayer/multiplaymgr.hxx>
#include <FDM/fdm_shell.hxx>
@ -1272,140 +1268,6 @@ void fgInitView() {
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
// initialization routines. If you are adding a subsystem to flight
// gear, its initialization call should located in this routine.
@ -1528,17 +1390,6 @@ bool fgInitSubsystems() {
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.
////////////////////////////////////////////////////////////////////
@ -1714,10 +1565,7 @@ void fgReInitSubsystems()
globals->get_controls()->reset_all();
fgUpdateLocalTime();
// re-init to proper time of day setting
fgInitTimeOffset();
globals->get_subsystem("time")->reinit();
if ( !freeze ) {
fgSetBool("/sim/freeze/master", false);
@ -1743,11 +1591,6 @@ void doSimulatorReset(void) // from gui_local.cxx -- TODO merge with fgReInitSu
// update our position based on current presets
fgInitPosition();
SGTime *t = globals->get_time_params();
delete t;
t = fgInitTime();
globals->set_time_params(t);
fgReInitSubsystems();
globals->get_tile_mgr()->update(fgGetDouble("/environment/visibility-m"));

View file

@ -79,14 +79,6 @@ bool fgInitPosition();
// Listen to /sim/tower/airport-id and set tower view position accordingly
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
* for <aircraft>-set.xml configuration files and show the aircaft name

View file

@ -34,8 +34,6 @@
#include <iostream>
#include <plib/netSocket.h>
#include <osg/Camera>
#include <osg/GraphicsContext>
#include <osgDB/Registry>
@ -67,7 +65,7 @@
#include <Sound/fg_fx.hxx>
#include <ATCDCL/ATCmgr.hxx>
#include <ATCDCL/AIMgr.hxx>
#include <Time/tmp.hxx>
#include <Time/TimeManager.hxx>
#include <Environment/environment_mgr.hxx>
#include <Environment/ephemeris.hxx>
#include <GUI/new_gui.hxx>
@ -85,8 +83,6 @@
#include "WindowSystemAdapter.hxx"
#include <Main/viewer.hxx>
static double real_delta_time_sec = 0.0;
double delta_time_sec = 0.0;
using namespace flightgear;
@ -99,10 +95,7 @@ FGGeneral general;
// our initializations out of the idle callback so that we can get a
// splash screen up and running right away.
int idle_state = 0;
long global_multi_loop;
SGTimeStamp last_time_stamp;
SGTimeStamp current_time_stamp;
void fgInitSoundManager();
void fgSetNewSoundDevice(const char *);
@ -114,8 +107,7 @@ extern int _bootstrap_OSInit;
// What should we do when we have nothing else to do? Let's get ready
// for the next move and update the display?
static void fgMainLoop( void ) {
int model_hz = fgGetInt("/sim/model-hz");
static SGConstPropertyNode_ptr longitude
= fgGetNode("/position/longitude-deg");
static SGConstPropertyNode_ptr latitude
@ -128,172 +120,24 @@ static void fgMainLoop( void ) {
= fgGetNode("/velocities/speed-east-fps");
static SGConstPropertyNode_ptr vd_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
= fgGetNode("/sim/signals/frame", true);
frame_signal->fireValueChanged();
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, "======= ==== ====");
// update "time"
static bool last_clock_freeze = false;
if ( clock_freeze->getBoolValue() ) {
// clock freeze requested
if ( cur_time_override->getLongValue() == 0 ) {
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() );
// update "time"
double sim_dt, real_dt;
TimeManager* timeMgr = (TimeManager*) globals->get_subsystem("time");
// compute simulated time (allowing for pause, warp, etc) and
// real elapsed time
timeMgr->computeTimeDeltas(sim_dt, real_dt);
if (globals->get_warp_delta() != 0) {
FGLight *l = (FGLight *)(globals->get_subsystem("lighting"));
l->update( 0.5 );
@ -307,36 +151,6 @@ static void fgMainLoop( void ) {
altitude->getDoubleValue() * SG_FEET_TO_METER,
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
// implementation is an AI model and depends on that
@ -345,7 +159,7 @@ static void fgMainLoop( void ) {
#if ENABLE_ATCDCL
// Run ATC subsystem
if (fgGetBool("/sim/atc/enabled"))
globals->get_ATC_mgr()->update(delta_time_sec);
globals->get_ATC_mgr()->update(sim_dt);
// Run the AI subsystem
@ -356,11 +170,11 @@ static void fgMainLoop( void ) {
// depricated AI_mgr system. So, we can safely skip the following
// two lines at compile time when compiling with --disable-atcdcl
if (fgGetBool("/sim/ai-traffic/enabled"))
globals->get_AI_mgr()->update(delta_time_sec);
globals->get_AI_mgr()->update(sim_dt);
#endif
globals->get_subsystem_mgr()->update(delta_time_sec);
globals->get_aircraft_model()->update(delta_time_sec);
globals->get_subsystem_mgr()->update(sim_dt);
globals->get_aircraft_model()->update(sim_dt);
//
// Tile Manager updates - see if we need to load any new scenery tiles.
@ -376,14 +190,14 @@ static void fgMainLoop( void ) {
globals->get_tile_mgr()->update(geodViewPos, visibility_meters);
// run Nasal's settimer() loops right before the view manager
globals->get_event_mgr()->update(delta_time_sec);
globals->get_event_mgr()->update(sim_dt);
// pick up model coordidnates that Nasal code may have set relative to the
// aircraft's
globals->get_model_mgr()->update(delta_time_sec);
globals->get_model_mgr()->update(sim_dt);
// update the view angle as late as possible, but before sound calculations
globals->get_viewmgr()->update(real_delta_time_sec);
globals->get_viewmgr()->update(real_dt);
// 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-
@ -419,13 +233,13 @@ static void fgMainLoop( void ) {
if (smgr_enabled == true) {
static SGPropertyNode *volume = fgGetNode("/sim/sound/volume");
smgr->set_volume(volume->getFloatValue());
smgr->update(delta_time_sec);
smgr->update(sim_dt);
}
}
#endif
// END Tile Manager udpates
bool scenery_loaded = fgGetBool("sim/sceneryloaded");
if (!scenery_loaded && globals->get_tile_mgr()->isSceneryLoaded()
&& fgGetBool("sim/fdm-initialized")) {
fgSetBool("sim/sceneryloaded",true);
@ -566,9 +380,10 @@ static void fgIdleFunction ( void ) {
fgInitPosition();
fgInitTowerLocationListener();
SGTime *t = fgInitTime();
globals->set_time_params( t );
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,
@ -733,10 +548,7 @@ static void fgIdleFunction ( void ) {
} else if ( idle_state == 8 ) {
idle_state = 1000;
// Initialize the time offset (warp) after fgInitSubsystem
// (which initializes the lighting interpolation tables.)
fgInitTimeOffset();
// setup OpenGL view parameters
globals->get_renderer()->init();

View file

@ -8,8 +8,6 @@ bool fgMainInit( int argc, char **argv );
extern int idle_state;
extern long global_multi_loop;
extern double delta_time_sec;
extern char *homedir;
extern char *hostname;

View file

@ -563,16 +563,12 @@ FGRenderer::init( void )
// Update all Visuals (redraws anything graphics related)
void
FGRenderer::update( bool refresh_camera_settings ) {
bool scenery_loaded = fgGetBool("sim/sceneryloaded")
bool scenery_loaded = fgGetBool("sim/sceneryloaded", false)
|| fgGetBool("sim/sceneryloaded-override");
osgViewer::Viewer* viewer = globals->get_renderer()->getViewer();
if ( idle_state < 1000 || !scenery_loaded ) {
fgSetDouble("/sim/startup/splash-alpha", 1.0);
// 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;
if (!scenery_loaded) {
fgSetDouble("/sim/startup/splash-alpha", 1.0);
return;
}
// Fade out the splash screen over the first three seconds.
@ -629,9 +625,7 @@ FGRenderer::update( bool refresh_camera_settings ) {
thesky->set_visibility(visibility_meters);
double altitude_m = fgGetDouble("/position/altitude-ft") * SG_FEET_TO_METER;
thesky->modify_vis( altitude_m,
( global_multi_loop * fgGetInt("/sim/speed-up") )
/ (double)fgGetInt("/sim/model-hz") );
thesky->modify_vis( altitude_m, 0.0 /* time factor, now unused */);
// update the sky dome
if ( skyblend ) {
@ -673,7 +667,8 @@ FGRenderer::update( bool refresh_camera_settings ) {
scolor.cloud_color = SGVec3f(l->cloud_color().data());
scolor.sun_angle = l->get_sun_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->repaint( scolor, *globals->get_ephem() );

View file

@ -31,7 +31,6 @@
#include <simgear/timing/sg_time.hxx>
#include <FDM/flightProperties.hxx>
#include <Time/tmp.hxx>
#include <Main/fg_props.hxx>
#include <Main/globals.hxx>
#include <Scenery/scenery.hxx>

View file

@ -30,7 +30,6 @@
#include <simgear/io/iochannel.hxx>
#include <simgear/timing/sg_time.hxx>
#include <Time/tmp.hxx>
#include <Main/fg_props.hxx>
#include <Main/globals.hxx>
#include <Scenery/scenery.hxx>

View file

@ -3,6 +3,6 @@ noinst_LIBRARIES = libTime.a
libTime_a_SOURCES = \
light.cxx light.hxx \
sunsolver.cxx sunsolver.hxx \
tmp.cxx tmp.hxx
TimeManager.cxx TimeManager.hxx
INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/src

359
src/Time/TimeManager.cxx Normal file
View file

@ -0,0 +1,359 @@
// 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() );
}

78
src/Time/TimeManager.hxx Normal file
View file

@ -0,0 +1,78 @@
// 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

View file

@ -36,6 +36,8 @@
#include <simgear/misc/sg_path.hxx>
#include <simgear/scene/sky/sky.hxx>
#include <simgear/screen/colors.hxx>
#include <simgear/timing/sg_time.hxx>
#include <simgear/structure/event_mgr.hxx>
#include <Main/main.hxx>
#include <Main/globals.hxx>
@ -44,7 +46,38 @@
#include <Main/viewer.hxx>
#include "light.hxx"
#include "tmp.hxx"
#include "sunsolver.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
@ -114,6 +147,9 @@ void FGLight::init () {
SGPath sky_path = path;
sky_path.append( "Lighting/sky" );
_sky_tbl = new SGInterpTable( sky_path.str() );
globals->get_event_mgr()->addTask("updateSunPos", this,
&FGLight::updateSunPos, 0.5 );
}
@ -128,8 +164,7 @@ void FGLight::reinit () {
init();
fgUpdateSunPos();
updateSunPos();
update_sky_color();
update_adj_fog_color();
}
@ -188,18 +223,12 @@ void FGLight::unbind () {
// update lighting parameters based on current sun position
void FGLight::update( double dt ) {
_dt_total += dt;
if (_dt_total >= 0.5) {
_dt_total -= 0.5;
fgUpdateSunPos();
}
void FGLight::update( double dt )
{
update_adj_fog_color();
if (_prev_sun_angle != _sun_angle) {
_prev_sun_angle = _sun_angle;
_prev_sun_angle = _sun_angle;
update_sky_color();
}
}
@ -382,3 +411,101 @@ void FGLight::update_adj_fog_color () {
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;
}

View file

@ -102,6 +102,8 @@ private:
void update_sky_color ();
void update_adj_fog_color ();
void updateSunPos();
// properties for chrome light; not a tie because I want to fire
// property listeners when the values change.
SGPropertyNode_ptr _chromeProps[4];

View file

@ -37,7 +37,6 @@
#include <Main/globals.hxx>
#include <Main/fg_props.hxx>
#include "tmp.hxx"
#include "sunsolver.hxx"

View file

@ -1,238 +0,0 @@
// 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
}

View file

@ -1,45 +0,0 @@
// 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