public void Tick() { double current_frame_time = Platform.GetPerformanceCounter(); double delta_time = current_frame_time - _prevFrameTime; _prevFrameTime = current_frame_time; // Handle unexpected timer anomalies (overflow, extra slow frames, etc) if (delta_time > _desiredFrametime * 8) { delta_time = _desiredFrametime; } if (delta_time < 0) { delta_time = 0; } // VSync Time Snapping for (int i = 0; i < _snapFreqs.Length; ++i) { var snap_freq = _snapFreqs[i]; if (Math.Abs(delta_time - snap_freq) < _vsyncMaxError) { delta_time = snap_freq; break; } } // Delta Time Averaging for (int i = 0; i < TimeHistoryCount - 1; ++i) { _timeAverager[i] = _timeAverager[i + 1]; } _timeAverager[TimeHistoryCount - 1] = delta_time; delta_time = 0; for (int i = 0; i < TimeHistoryCount; ++i) { delta_time += _timeAverager[i]; } delta_time /= TimeHistoryCount; // Add To Accumulator _frameAccum += delta_time; // Spiral of Death Protection if (_frameAccum > _desiredFrametime * 8) { _resync = true; } // Timer Resync Requested if (_resync) { _frameAccum = 0; delta_time = _desiredFrametime; _resync = false; } // Process Events and Input Engine.ProcessEvents(); Engine.ProcessInput(); // Unlocked Frame Rate, Interpolation Enabled if (UnlockFrameRate) { double consumed_delta_time = delta_time; while (_frameAccum >= _desiredFrametime) { FixedUpdate((float)_fixedDeltatime); // Cap Variable Update's dt to not be larger than fixed update, // and interleave it (so game state can always get animation frame it needs) if (consumed_delta_time > _desiredFrametime) { Update((float)_fixedDeltatime); consumed_delta_time -= _desiredFrametime; } _frameAccum -= _desiredFrametime; } Update((float)(consumed_delta_time / Platform.GetPerformanceFrequency())); if (Engine.Canvas.NeedsResetDisplay) { Engine.Canvas.HandleDisplayChange(); OnDisplayResize(); } Draw(Engine.Canvas, (float)(_frameAccum / _desiredFrametime)); GraphicsContext.Frame(); } // Locked Frame Rate, No Interpolation else { while (_frameAccum >= _desiredFrametime * UpdateMult) { for (int i = 0; i < UpdateMult; ++i) { FixedUpdate((float)_fixedDeltatime); Update((float)_fixedDeltatime); _frameAccum -= _desiredFrametime; } } if (Engine.Canvas.NeedsResetDisplay) { Engine.Canvas.HandleDisplayChange(); OnDisplayResize(); } Draw(Engine.Canvas, 1.0f); GraphicsContext.Frame(); } }