GetRealisticFPS()

Share your advanced PureBasic knowledge/code with the community.
User avatar
Rescator
Addict
Addict
Posts: 1769
Joined: Sat Feb 19, 2005 5:05 pm
Location: Norway

GetRealisticFPS()

Post by Rescator »

Wasn't sure what to call this, GetRealisticFPS() was the only thing I could think of,
found this source kicking around and decided to share it, it probably could be optimized some so have at it if anyone feel like it.
Public Domain.

Code: Select all

;If you use timeBeginPeriod_(ms) and timeEndPeriod_(ms)
;you can achieve a pretty stable framerate.
;But at a cost of system overhead as all timers that rely on the system timer resolution
;is also affected, due to this MicroSoft changed latest Windows Media Player to use 5ms system timer resolution.
;In my own tests I also found 5m to give the least timer flutter when
;using timeGetTime_() and Delay() or Sleep_()

;The following simple code lets you list "usable" resolutions vs framerates (Press F5 to compile with debugger).
;Or (Press Shift+F5 to compile without debugger) enter your preferred framerate and get a realistic framerate in return.
;Realistic framerates are those that either can be represented directly i milliseconds,
;or are a multiple of your desired framerate in some way (frame doubling and frame halving)
;which should make your graphics timings and calculations a lot easier.

;GetRealisticFPS() tries to return an exact match, or the nearest (up or down) match to your desired FPS,
;if it fails it will return 0 fps, meaning you either input an invalid FPS or you need to use dynamic framerate (FPS throttling) instead.

;Public Domain

EnableExplicit

Procedure.l GetRealisticFPS(fps.l)
 Protected result.l,min.l,max.l,f.l,x.l
 If (fps>=1) And (fps<=1000)
  If Not (1000%fps)
   result=fps
  Else
   f=fps
   Repeat
    If Not (f%2)
     x=f/2
		   If Not (1000%x)
		    min=x
		   Else
		    f=x
		   EndIf
		  Else
		   f=0
	   EndIf
	  Until min Or (f<1)
   f=fps
   Repeat
    x=f*2
	   If Not (1000%x)
	    max=x
	   Else
	    f=x
	   EndIf
	  Until max Or (f>1000)
	  If max And min
	   If (max-fps)<(fps-min)
	    result=max
	   Else
	    result=min
	   EndIf
		 ElseIf min Or max
		  If max
	 	  result=max
	 	 ElseIf min
	 	  result=min
	 	 EndIf
	 	Else
	   For f=fps To 1 Step -1
	    If Not (1000%f)
	     min=f
	    EndIf
	   Next
	   For f=fps To 1000
	    If Not (1000%f)
	     max=f
	    EndIf
	   Next
	  EndIf
  EndIf
 EndIf
 ProcedureReturn result
EndProcedure

Define desiredfps.l,realisticfps.l,text$

CompilerIf #PB_Compiler_Debugger

 Define i.i
	For i=0 To 1001
	 realisticfps=GetRealisticFPS(i)
	 If realisticfps
	  Debug Str(i)+" = "+Str(realisticfps)
	 EndIf
	Next

CompilerElse

	desiredfps=Val(InputRequester("FPS Timing Calculator","Enter desired FPS",""))
	If desiredfps
	 realisticfps=GetRealisticFPS(desiredfps)
	 If Not realisticfps
	  text$=Str(desiredfps)+" FPS is not achievable without dynamic timings."
	 ElseIf desiredfps<>realisticfps
	  text$=Str(desiredfps)+" FPS is achievable by frame "
	  If desiredfps<realisticfps
	   text$+"doubling"
	  Else
	   text$+"halving"
	  EndIf
	  text$+"."+#LF$+#LF$
	  text$+"A timing of "+Str(1000/realisticfps)+" ms is needed to get "+Str(realisticfps)+" FPS."+#LF$+#LF$
	  text$+"Use a divisor of "+Str(desiredfps/realisticfps)+" or multiply by "+StrF(realisticfps/desiredfps)+" and"+#LF$
	  text$+"a multiplicator of "+Str(desiredfps/realisticfps)+" or "+StrF(desiredfps/realisticfps)+" to"+#LF$
	  text$+"to calculate from/to the actual framerate."
	 Else
	  text$=Str(desiredfps)+" FPS is realistic and simply needs a timing resolution of "+Str(1000/desiredfps)+" ms."
	 EndIf
	 MessageRequester("Realistic FPS",text$)
	EndIf

CompilerEndIf