@@ -52,6 +52,7 @@ public abstract class Overlay : IDisposable
5252 private Thread renderThread ;
5353 private volatile CancellationTokenSource cancellationTokenSource ;
5454 private volatile bool overlayIsReady ;
55+ private int fpslimit ;
5556
5657 private Dictionary < string , ( IntPtr Handle , uint Width , uint Height ) > loadedTexturesPtrs ;
5758
@@ -150,7 +151,8 @@ public Overlay(string windowTitle, bool DPIAware, int windowWidth, int windowHei
150151 {
151152 this . initialWindowWidth = windowWidth ;
152153 this . initialWindowHeight = windowHeight ;
153- this . VSync = true ;
154+ this . VSync = false ;
155+ this . FPSLimit = 60 ;
154156 this . _disposedValue = false ;
155157 this . overlayIsReady = false ;
156158 this . title = windowTitle ;
@@ -311,9 +313,38 @@ public unsafe bool ReplaceFont(FontHelper.FontLoadDelegate fontLoadDelegate)
311313
312314 /// <summary>
313315 /// Enable or disable the vsync on the overlay.
316+ /// You can either use the <see cref="FPSLimit"/> or <see cref="VSync"/>.
317+ /// VSync will be given the preference if both are set.
314318 /// </summary>
315319 public bool VSync ;
316320
321+ /// <summary>
322+ /// Gets or sets the FPS Limits of the overlay.
323+ /// You can either use the <see cref="FPSLimit"/> or <see cref="VSync"/>.
324+ /// VSync will be given the preference if both are set.
325+ /// </summary>
326+ public int FPSLimit
327+ {
328+ get => this . fpslimit ;
329+ set
330+ {
331+ if ( value == 0 )
332+ {
333+ this . fpslimit = value ;
334+ _ = Winmm . MM_EndPeriod ( 1 ) ;
335+ }
336+ else if ( value > 0 )
337+ {
338+ this . fpslimit = value ;
339+ _ = Winmm . MM_BeginPeriod ( 1 ) ;
340+ }
341+ else
342+ {
343+ // ignore negative values.
344+ }
345+ }
346+ }
347+
317348 /// <summary>
318349 /// Gets or sets the position of the overlay window.
319350 /// </summary>
@@ -444,6 +475,11 @@ protected virtual void Dispose(bool disposing)
444475
445476 if ( disposing )
446477 {
478+ if ( this . FPSLimit > 0 )
479+ {
480+ Winmm . MM_EndPeriod ( 1 ) ;
481+ }
482+
447483 this . renderThread ? . Join ( ) ;
448484 foreach ( var key in this . loadedTexturesPtrs . Keys . ToArray ( ) )
449485 {
@@ -491,22 +527,35 @@ protected virtual Task PostInitialized()
491527 private void RunInfiniteLoop ( CancellationToken token )
492528 {
493529 var stopwatch = Stopwatch . StartNew ( ) ;
494- float deltaTime = 0f ;
530+ var currentTimeSec = 0f ;
495531 var clearColor = new Color4 ( 0.0f ) ;
532+ var delayMs = 0f ;
533+ var sleepTimeMs = 0 ;
496534 while ( ! token . IsCancellationRequested )
497535 {
498- deltaTime = stopwatch . ElapsedTicks / ( float ) Stopwatch . Frequency ;
536+ currentTimeSec = stopwatch . ElapsedTicks / ( float ) Stopwatch . Frequency ;
499537 stopwatch . Restart ( ) ;
500538 this . window . PumpEvents ( ) ;
501539 Utils . SetOverlayClickable ( this . window . Handle , this . inputhandler . Update ( ) ) ;
502- this . renderer . Update ( deltaTime , ( ) => { Render ( ) ; } ) ;
540+ this . renderer . Update ( currentTimeSec , ( ) => { Render ( ) ; } ) ;
503541 this . deviceContext . OMSetRenderTargets ( renderView ) ;
504542 this . deviceContext . ClearRenderTargetView ( renderView , clearColor ) ;
505543 this . renderer . Render ( ) ;
506544 if ( VSync )
507545 {
508546 this . swapChain . Present ( 1 , PresentFlags . None ) ; // Present with vsync
509547 }
548+ else if ( this . FPSLimit > 0 )
549+ {
550+ this . swapChain . Present ( 0 , PresentFlags . None ) ;
551+ delayMs = 1000f / this . FPSLimit ;
552+ currentTimeSec = stopwatch . ElapsedTicks / ( float ) Stopwatch . Frequency ;
553+ sleepTimeMs = ( int ) ( delayMs - ( currentTimeSec * 1000 ) ) ;
554+ if ( sleepTimeMs > 0 )
555+ {
556+ Thread . Sleep ( sleepTimeMs ) ;
557+ }
558+ }
510559 else
511560 {
512561 this . swapChain . Present ( 0 , PresentFlags . None ) ; // Present without vsync
0 commit comments