>
</File>
<File
- RelativePath="..\..\..\src\Time\TimeManager.cxx"
+ RelativePath="..\..\..\src\Time\tmp.cxx"
>
</File>
<File
- RelativePath="..\..\..\src\Time\TimeManager.hxx"
+ RelativePath="..\..\..\src\Time\tmp.hxx"
>
</File>
</Filter>
#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();
- globals->get_subsystem("time")->reinit();
+ fgUpdateLocalTime();
+
+ // re-init to proper time of day setting
+ fgInitTimeOffset();
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/fg_fx.hxx>
#include <ATCDCL/ATCmgr.hxx>
#include <ATCDCL/AIMgr.hxx>
-#include <Time/TimeManager.hxx>
+#include <Time/tmp.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"
- 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);
-
+
+ // 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() );
+
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(sim_dt);
+ globals->get_ATC_mgr()->update(delta_time_sec);
// Run the AI subsystem
// 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(sim_dt);
+ globals->get_AI_mgr()->update(delta_time_sec);
#endif
- globals->get_subsystem_mgr()->update(sim_dt);
- globals->get_aircraft_model()->update(sim_dt);
+ globals->get_subsystem_mgr()->update(delta_time_sec);
+ globals->get_aircraft_model()->update(delta_time_sec);
//
// 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(sim_dt);
+ globals->get_event_mgr()->update(delta_time_sec);
// pick up model coordidnates that Nasal code may have set relative to the
// aircraft's
- globals->get_model_mgr()->update(sim_dt);
+ globals->get_model_mgr()->update(delta_time_sec);
// update the view angle as late as possible, but before sound calculations
- globals->get_viewmgr()->update(real_dt);
+ globals->get_viewmgr()->update(real_delta_time_sec);
// Update the sound manager last so it can use the CPU while the GPU
// 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(sim_dt);
+ smgr->update(delta_time_sec);
}
}
#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();
- TimeManager* t = new TimeManager;
- globals->add_subsystem("time", t, SGSubsystemMgr::INIT);
- t->init(); // need to init now, not during initSubsystems
-
+ SGTime *t = fgInitTime();
+ globals->set_time_params( t );
+
// Do some quick general initializations
if( !fgInitGeneral()) {
SG_LOG( SG_GENERAL, SG_ALERT,
} 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", false)
+ bool scenery_loaded = fgGetBool("sim/sceneryloaded")
|| fgGetBool("sim/sceneryloaded-override");
osgViewer::Viewer* viewer = globals->get_renderer()->getViewer();
- if (!scenery_loaded) {
- fgSetDouble("/sim/startup/splash-alpha", 1.0);
- return;
+ 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;
}
// 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, 0.0 /* time factor, now unused */);
+ thesky->modify_vis( altitude_m,
+ ( global_multi_loop * fgGetInt("/sim/speed-up") )
+ / (double)fgGetInt("/sim/model-hz") );
// update the sky dome
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 \
- TimeManager.cxx TimeManager.hxx
+ tmp.cxx tmp.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);
-
- 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() );
-}
+++ /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 "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;
-}
+#include "tmp.hxx"
// 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();
- updateSunPos();
+ fgUpdateSunPos();
+
update_sky_color();
update_adj_fog_color();
}
// update lighting parameters based on current sun position
-void FGLight::update( double dt )
-{
+void FGLight::update( double dt ) {
+
+ _dt_total += dt;
+ if (_dt_total >= 0.5) {
+ _dt_total -= 0.5;
+ fgUpdateSunPos();
+ }
+
update_adj_fog_color();
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
+