/// <summary> /// Updates the specified context. /// </summary> /// <param name="uv">The Ultraviolet context to update.</param> /// <param name="time">Time elapsed since the last update.</param> /// <returns><see langword="true"/> if the host should continue processing; otherwise, <see langword="false"/>.</returns> private Boolean UpdateContext(UltravioletContext uv, UltravioletTime time) { using (UltravioletProfiler.Section(UltravioletProfilerSections.Update)) { uv.Update(time); } return(!uv.Disposed); }
/// <summary> /// Advances the application state by one tick. /// </summary> public void RunOneTick() { var uv = host.Ultraviolet; if (!host.IsActive && InactiveSleepTime.TotalMilliseconds > 0) { Thread.Sleep(InactiveSleepTime); } var syncContext = SynchronizationContext.Current as UltravioletSynchronizationContext; if (syncContext != null) { syncContext.ProcessWorkItems(); } if (IsFixedTimeStep) { if (tickTimer.Elapsed.TotalMilliseconds >= targetElapsedTime.TotalMilliseconds) { tickTimer.Restart(); tickElapsed -= targetElapsedTime.TotalMilliseconds * (int)(tickElapsed / targetElapsedTime.TotalMilliseconds); uv.HandleFrameStart(); const Double CatchUpThreshold = 1.05; if (frameElapsed > 0 && frameElapsed > targetElapsedTime.TotalMilliseconds * CatchUpThreshold) { const Int32 RunningSlowlyFrameCount = 5; runningSlowlyFrames = RunningSlowlyFrameCount; isRunningSlowly = true; const Int32 CatchUpFrameLimit = 10; var catchUpUpdates = Math.Min(CatchUpFrameLimit, (int)(frameElapsed / targetElapsedTime.TotalMilliseconds)); for (int i = 0; i < catchUpUpdates; i++) { timeTrackerUpdate.Increment(targetElapsedTime, isRunningSlowly); timeTrackerDraw.Increment(targetElapsedTime, isRunningSlowly); if (!UpdateContext(uv, timeTrackerUpdate.Time)) { return; } } } else { if (isRunningSlowly) { runningSlowlyFrames--; if (runningSlowlyFrames == 0) { isRunningSlowly = false; } } } frameTimer.Restart(); var uvTimeUpdate = timeTrackerUpdate.Increment(targetElapsedTime, isRunningSlowly); if (!UpdateContext(uv, uvTimeUpdate)) { return; } if (!host.IsSuspended) { var uvTimeDraw = timeTrackerDraw.Increment(targetElapsedTime, isRunningSlowly); using (UltravioletProfiler.Section(UltravioletProfilerSections.Draw)) { uv.Draw(uvTimeDraw); } } uv.HandleFrameEnd(); frameElapsed = frameTimer.Elapsed.TotalMilliseconds; } else { // NOTE: The precision of Sleep() can generally be assumed to be something like 10-15ms, so // we only call it if we know we're going to be waiting a long time and there's no point // in sucking up CPU cycles spinning our loop. var frameDelay = (int)(targetElapsedTime.TotalMilliseconds - tickTimer.Elapsed.TotalMilliseconds); if (frameDelay >= 10) { Thread.Sleep(frameDelay); } } } else { var time = tickTimer.Elapsed.TotalMilliseconds; tickTimer.Restart(); uv.HandleFrameStart(); var uvTimeDelta = TimeSpan.FromTicks((long)(time * TimeSpan.TicksPerMillisecond)); var uvTimeUpdate = timeTrackerUpdate.Increment(uvTimeDelta, false); if (!UpdateContext(uv, uvTimeUpdate)) { return; } if (!host.IsSuspended) { var uvTimeDraw = uvTimeUpdate; using (UltravioletProfiler.Section(UltravioletProfilerSections.Draw)) { uv.Draw(uvTimeDraw); } } uv.HandleFrameEnd(); } }