Remove the unfortunately named 'tmp.[cxx|hxx]', pushing the remaining code in FGLight.
(second try, with init bug fixed)
>
</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>
ephem_data_path.append("Astro");
_impl = new SGEphemeris(ephem_data_path.c_str());
globals->set_ephem(_impl);
+
+ _latProp = fgGetNode("/position/latitude-deg", true);
+ update(0.0);
}
void Ephemeris::postinit()
{
- update(0.0);
+
}
static void tieStar(const char* prop, Star* s, double (Star::*getter)() const)
void Ephemeris::bind()
{
- _latProp = fgGetNode("/position/latitude-deg", true);
-
tieStar("/ephemeris/sun/xs", _impl->get_sun(), &Star::getxs);
tieStar("/ephemeris/sun/ys", _impl->get_sun(), &Star::getys);
tieStar("/ephemeris/sun/ze", _impl->get_sun(), &Star::getze);
#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"
#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>
#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>
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.
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.
////////////////////////////////////////////////////////////////////
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);
// 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"));
// 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
#include <iostream>
-#include <plib/netSocket.h>
-
#include <osg/Camera>
#include <osg/GraphicsContext>
#include <osgDB/Registry>
#include <Sound/morse.hxx>
#include <Sound/fg_fx.hxx>
#include <ATCDCL/ATCmgr.hxx>
-#include <Time/tmp.hxx>
+#include <Time/TimeManager.hxx>
#include <Environment/environment_mgr.hxx>
#include <Environment/ephemeris.hxx>
#include <GUI/new_gui.hxx>
#include "WindowSystemAdapter.hxx"
#include <Main/viewer.hxx>
-static double real_delta_time_sec = 0.0;
-double delta_time_sec = 0.0;
using namespace flightgear;
// 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 *);
// 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
= 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 );
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
#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);
#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.
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-
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);
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,
// Initialize the sky
Ephemeris* eph = new Ephemeris;
- globals->add_subsystem("ephmeris", eph);
+ globals->add_subsystem("ephemeris", eph);
eph->init(); // FIXME - remove this once SGSky code below is also a subsystem
eph->bind();
} 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();
extern int idle_state;
-extern long global_multi_loop;
-extern double delta_time_sec;
extern char *homedir;
extern char *hostname;
// 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.
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 ) {
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() );
#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>
#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>
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
--- /dev/null
+// 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);
+
+// 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() );
+}
--- /dev/null
+// 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
#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>
#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
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 );
}
init();
- fgUpdateSunPos();
-
+ updateSunPos();
update_sky_color();
update_adj_fog_color();
}
// 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();
}
}
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;
+
+}
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];
#include <Main/globals.hxx>
#include <Main/fg_props.hxx>
-#include "tmp.hxx"
#include "sunsolver.hxx"
+++ /dev/null
-// 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
-}
-
+++ /dev/null
-// 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
-