- // 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;
-
- // 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, "======= ==== ====");
-
- // Fix elevation. I'm just sticking this here for now, it should
- // probably move eventually
-
- /* printf("Before - ground = %.2f runway = %.2f alt = %.2f\n",
- scenery.get_cur_elev(),
- cur_fdm_state->get_Runway_altitude() * SG_FEET_TO_METER,
- cur_fdm_state->get_Altitude() * SG_FEET_TO_METER); */
-
- /* printf("Adjustment - ground = %.2f runway = %.2f alt = %.2f\n",
- scenery.get_cur_elev(),
- cur_fdm_state->get_Runway_altitude() * SG_FEET_TO_METER,
- cur_fdm_state->get_Altitude() * SG_FEET_TO_METER); */
-
- // cout << "Warp = " << globals->get_warp() << endl;
-
- // 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 );
- }