Example #1
0
 /// <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);
 }
Example #2
0
        /// <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();
            }
        }
Example #3
0
        /// <inheritdoc/>
        public void RunOneTick()
        {
            var uv = host.Ultraviolet;

            if (SynchronizationContext.Current is UltravioletSynchronizationContext syncContext)
            {
                syncContext.ProcessWorkItems();
            }

            UpdateSystemTimerResolution();

            if (InactiveSleepTime.Ticks > 0 && !host.IsActive)
            {
                Thread.Sleep(InactiveSleepTime);
            }

            var elapsedTicks = tickTimer.Elapsed.Ticks;

            tickTimer.Restart();

            accumulatedElapsedTime += elapsedTicks;
            if (accumulatedElapsedTime > MaxElapsedTime.Ticks)
            {
                accumulatedElapsedTime = MaxElapsedTime.Ticks;
            }

            var gameTicksToRun  = 0;
            var timeDeltaDraw   = default(TimeSpan);
            var timeDeltaUpdate = default(TimeSpan);

            if (IsFixedTimeStep)
            {
                gameTicksToRun = (Int32)(accumulatedElapsedTime / TargetElapsedTime.Ticks);
                if (gameTicksToRun > 0)
                {
                    lagFrames += (gameTicksToRun == 1) ? -1 : Math.Max(0, gameTicksToRun - 1);

                    if (lagFrames == 0)
                    {
                        runningSlowly = false;
                    }
                    if (lagFrames > 5)
                    {
                        runningSlowly = true;
                    }

                    timeDeltaUpdate         = TargetElapsedTime;
                    timeDeltaDraw           = TimeSpan.FromTicks(gameTicksToRun * TargetElapsedTime.Ticks);
                    accumulatedElapsedTime -= gameTicksToRun * TargetElapsedTime.Ticks;
                }
                else
                {
                    var frameDelay = (Int32)(TargetElapsedTime.TotalMilliseconds - tickTimer.Elapsed.TotalMilliseconds);
                    if (frameDelay >= 1 + systemTimerPeriod)
                    {
                        Thread.Sleep(frameDelay - 1);
                    }
                    return;
                }
            }
            else
            {
                gameTicksToRun = 1;
                if (forceElapsedTimeToZero)
                {
                    timeDeltaUpdate        = TimeSpan.Zero;
                    forceElapsedTimeToZero = false;
                }
                else
                {
                    timeDeltaUpdate = TimeSpan.FromTicks(elapsedTicks);
                    timeDeltaDraw   = timeDeltaUpdate;
                }
                accumulatedElapsedTime = 0;
                runningSlowly          = false;
            }

            if (gameTicksToRun == 0)
            {
                return;
            }

            uv.HandleFrameStart();

            for (var i = 0; i < gameTicksToRun; i++)
            {
                var updateTime = timeTrackerUpdate.Increment(timeDeltaUpdate, runningSlowly);
                if (!UpdateContext(uv, updateTime))
                {
                    return;
                }
            }

            if (!host.IsSuspended)
            {
                var drawTime = timeTrackerDraw.Increment(timeDeltaDraw, runningSlowly);
                using (UltravioletProfiler.Section(UltravioletProfilerSections.Draw))
                {
                    uv.Draw(drawTime);
                }
            }

            uv.HandleFrameEnd();
        }