diff --git a/ClickableTransparentOverlay/Overlay.cs b/ClickableTransparentOverlay/Overlay.cs index 25b8c4f..69b93de 100644 --- a/ClickableTransparentOverlay/Overlay.cs +++ b/ClickableTransparentOverlay/Overlay.cs @@ -52,6 +52,7 @@ public abstract class Overlay : IDisposable private Thread renderThread; private volatile CancellationTokenSource cancellationTokenSource; private volatile bool overlayIsReady; + private int fpslimit; private Dictionary loadedTexturesPtrs; @@ -150,7 +151,8 @@ public Overlay(string windowTitle, bool DPIAware, int windowWidth, int windowHei { this.initialWindowWidth = windowWidth; this.initialWindowHeight = windowHeight; - this.VSync = true; + this.VSync = false; + this.FPSLimit = 60; this._disposedValue = false; this.overlayIsReady = false; this.title = windowTitle; @@ -311,9 +313,38 @@ public unsafe bool ReplaceFont(FontHelper.FontLoadDelegate fontLoadDelegate) /// /// Enable or disable the vsync on the overlay. + /// You can either use the or . + /// VSync will be given the preference if both are set. /// public bool VSync; + /// + /// Gets or sets the FPS Limits of the overlay. + /// You can either use the or . + /// VSync will be given the preference if both are set. + /// + public int FPSLimit + { + get => this.fpslimit; + set + { + if (value == 0) + { + this.fpslimit = value; + _ = Winmm.MM_EndPeriod(1); + } + else if (value > 0) + { + this.fpslimit = value; + _ = Winmm.MM_BeginPeriod(1); + } + else + { + // ignore negative values. + } + } + } + /// /// Gets or sets the position of the overlay window. /// @@ -444,6 +475,11 @@ protected virtual void Dispose(bool disposing) if (disposing) { + if (this.FPSLimit > 0) + { + Winmm.MM_EndPeriod(1); + } + this.renderThread?.Join(); foreach(var key in this.loadedTexturesPtrs.Keys.ToArray()) { @@ -491,15 +527,17 @@ protected virtual Task PostInitialized() private void RunInfiniteLoop(CancellationToken token) { var stopwatch = Stopwatch.StartNew(); - float deltaTime = 0f; + var currentTimeSec = 0f; var clearColor = new Color4(0.0f); + var delayMs = 0f; + var sleepTimeMs = 0; while (!token.IsCancellationRequested) { - deltaTime = stopwatch.ElapsedTicks / (float)Stopwatch.Frequency; + currentTimeSec = stopwatch.ElapsedTicks / (float)Stopwatch.Frequency; stopwatch.Restart(); this.window.PumpEvents(); Utils.SetOverlayClickable(this.window.Handle, this.inputhandler.Update()); - this.renderer.Update(deltaTime, () => { Render(); }); + this.renderer.Update(currentTimeSec, () => { Render(); }); this.deviceContext.OMSetRenderTargets(renderView); this.deviceContext.ClearRenderTargetView(renderView, clearColor); this.renderer.Render(); @@ -507,6 +545,17 @@ private void RunInfiniteLoop(CancellationToken token) { this.swapChain.Present(1, PresentFlags.None); // Present with vsync } + else if (this.FPSLimit > 0) + { + this.swapChain.Present(0, PresentFlags.None); + delayMs = 1000f / this.FPSLimit; + currentTimeSec = stopwatch.ElapsedTicks / (float)Stopwatch.Frequency; + sleepTimeMs = (int)(delayMs - (currentTimeSec * 1000)); + if (sleepTimeMs > 0) + { + Thread.Sleep(sleepTimeMs); + } + } else { this.swapChain.Present(0, PresentFlags.None); // Present without vsync diff --git a/ClickableTransparentOverlay/Win32/Winmm.cs b/ClickableTransparentOverlay/Win32/Winmm.cs new file mode 100644 index 0000000..620b331 --- /dev/null +++ b/ClickableTransparentOverlay/Win32/Winmm.cs @@ -0,0 +1,16 @@ +namespace ClickableTransparentOverlay.Win32 +{ + using System; + using System.Runtime.InteropServices; + + internal static class Winmm + { + public const string LibraryName = "winmm.dll"; + + [DllImport(LibraryName, EntryPoint = "timeBeginPeriod")] + public static extern uint MM_BeginPeriod(uint uMilliseconds); + + [DllImport(LibraryName, EntryPoint = "timeEndPeriod")] + public static extern uint MM_EndPeriod(uint uMilliseconds); + } +} diff --git a/Examples/SimpleExample/SampleOverlay.cs b/Examples/SimpleExample/SampleOverlay.cs index e2c3f7d..2a14baa 100644 --- a/Examples/SimpleExample/SampleOverlay.cs +++ b/Examples/SimpleExample/SampleOverlay.cs @@ -7,20 +7,32 @@ internal class SampleOverlay : Overlay { private bool wantKeepDemoWindow = true; + private int FPSHelper; public SampleOverlay() : base(3840, 2160) { + this.FPSHelper = this.FPSLimit; } protected override Task PostInitialized() { - this.VSync = false; return Task.CompletedTask; } protected override void Render() { ImGui.ShowDemoWindow(ref wantKeepDemoWindow); + + if (ImGui.Begin("FPS Changer")) + { + if (ImGui.InputInt("Set FPS", ref FPSHelper)) + { + this.FPSLimit = this.FPSHelper; + } + + ImGui.End(); + } + if (!this.wantKeepDemoWindow) { this.Close();