{{fbdoc item="title" value="Lite regulation function to be integrated into user loop for FPS control"}}----
Controlling **FPS** (Frames Per Second) by using an **in-loop lite-regulating procedure**.

**Preamble:**

	The main objective of this regulation function is to minimize the CPU load which is added to that of the user's own code.
	Therefore, all dead times used by this function to control the user FPS (Frames per second) are generated using exclusively the SLEEP keyword (no CPU consuming waiting loops).
	
	But the exclusive use of the SLEEP keyword induces a limitation on the maximum accessible FPS value because the delay generated by SLEEP cannot drop below a limit value depending on the OS cycle period.
	A workaround is integrated into this regulation function to provide from values greater than this FPS limit value no longer a true FPS but an apparent FPS which seems to match the requested FPS.
	
	In addition, as the SLEEP keyword does not have a good accuracy on the generated delay, the FPS obtained fluctuates around the requested value.
	SLEEP also produces a temporal bias which varies over time, but whose average is corrected by the regulation function.

{{fbdoc item="section" value="1. Principles to overcome the penalizing behavior of SLEEP keyword"}}
	To implement the best regulation but based only on the SLEEP keyword, some bad behaviors as described above must be overcome or minimized.
	
	__Principle for measuring the minimum delay accessible with SLEEP__
		To evaluate the minimum delay 'tos' accessible with SLEEP, the duration of a sequence of ten 'Sleep 1, 1' is measured using the keyword TIMER and the time found is divided by ten.
		But this minimum value 'tos' is not directly usable because a margin must be added to it to preserve an almost linear regulation operation.
		The minimum usable value is thus fixed at '3 * tos / 2'.
		
		This calibration phase is executed automatically on the first call to the regulation function, or if the time measured is much different than the time ordered, or on request from the user thanks to an optional parameter of the function, or on opportunity measurements when the high limit of regulation is reached (when a heel value of delay with 'Sleep tos / 2, 1' is used).
		
	__Principle for accessing an apparent FPS higher than the maximum true FPS accessible with SLEEP__
		When for a required FPS value, the 't' value to be applied in 'Sleep t, 1' becomes less than '3 * tos / 2', an 'image skipping' feature is started to provide an apparent FPS which matches to the required FPS.
		
		The basic principle of 'image skipping' is to remove all delays between these images (the regulation function returns immediately) so that the persistence of these images is low compared to that which is followed by a true delay.
		The smaller the image tracing time, the less these skipped images are visible.
		
		The temporal principle for skipping 'n - 1' images over 'n' images is to generate only one delay after viewing the last image, with a value such that the total period of the sequence (of 'n' images) is equal to 'n' times the period corresponding to the required FPS.
		The number of images to skip is stopped as soon as the only delay to generate for the sequence becomes greater than or equal to '3 * tos / 2'.
		When 'n - 1' images are skipped over 'n' images, the apparent FPS is equal to the inverse of the full display period of the 'n' images but multiplied by 'n'.
		
		This functionality of scrolling skipped images can be inhibited by the user thanks to an optional parameter of the function.
		
		Conversely, the user can reinforce this functionality by downright removing the skipped images by testing an optional parameter of the function which marks these skipped images.
		For this to work, the user code must very well separate the part of the code that concerns only the graphical drawing (the only part that should not be executed when the 'skipped image' tag is true) from the part of the code that concerns only the progress of the movement (which must always be executed). Otherwise, if these two parts of code are skipped at the same time (or even only a small portion of the progress of the movement), the graphical drawing will on the contrary be slowed down (although the returned FPS value says otherwise).
		
		This operating configuration ('image skipping' +'skipped image' user removing) is therefore the most efficient (from the point of view of apparent FPS) but imposes complete separation rules between two tasks (tracing only and calculating only) in the user animation code loop.
		
		On the other hand, the 'image skipping' configuration alone (with 'skipped image' scrolled by default) does not require any coding rules for the user.
		
		In case of too high requested FPS and to avoid having an image that is too jerky in the case of image skipping applied, the actual refresh rate of the screen cannot go below 10 Hz in case of skipped images (the apparent FPS can be very much higher), and the number of consecutive skipped images + 1 cannot exceed 20.
		These two limits when 'image skipping' is active induce an apparent displacement quasi-fluid for an initial image moving by 1 pixel every time (a displacement of 20 pixels at a frequency of 10 Hz appears to the user as a fairly smooth movement, not too jerky).
		
	__Principle for compensating for the average temporal bias produced by SLEEP__
		The principle is to measure (using the TIMER keyword) the real delay provided by 'Sleep t, 1' in relation with 't'.
		
		If the time measured is much different than the time ordered, this probably means that there is an error compared to the resolution measured on initialization, and the function then will automatically restart at the next call a new calibration phase (with ten 'Sleep 1, 1').
		Example: requested time = 4 µs, but measured time = 16 µs, probably because the resolution was changed (lowered) while program running.
		
		If the time measured is only a little different from the time ordered, the differences are averaged to try to correct the average bias of the SLEEP keyword.
		
{{fbdoc item="section" value="2. Description of the function body to include"}}
	The 'regulateLite()' function is described here.
	The code is not thread safe because it uses 'Static' variables.
	
	The function is well suited to regulate the FPS of an image refresh by inserting a delay into the loop, without adding a notable CPU load to that of the user's own code.
	
	**Note:** Like any waiting feature, it is strongly discouraged to use 'regulateLite()' when the screen is locked, so no call from inside a ""[ScreenLock...ScreenUnlock]"" block.
	
	The function has a mandatory first parameter ""'MyFps'"" through which the user passes their required FPS.
	
	For debugging purposes, the function returns the FPS (true or apparent) value it applied. If the user does not wish to use this debug data, then they can call the function as a Sub quite simply.
	If this returned FPS value is much lower than that required, this means that it becomes difficult to reach the FPS setpoint. Otherwise, the fluctuation of the FPS returned is mainly due the use of the only SLEEP keyword to generate the delay in the loop.
	
	Otherwise, the function proposes 3 optional parameters: 
			**""-""** ""'Restart'"" ('False' by default):
					This input parameter allows the user to force a new calibration phase, because for example he knows that the resolution of the OS cycle has just changed.
					Set this parameter to 'True' in the call, then to 'False' on the next call.
			**""-""** ""'SkipImage'"" ('True' by default):
					This input parameter allows the user to inhibit the automatic 'image skipping' feature. Whatever happens, there will be no skipped images, but perhaps to the detriment of the FPS obtained which may not follow the requested FPS.
					Set this parameter to 'False' to disable the 'image skipping' feature (can be reset to 'True' later).
			**""-""** ""'ImageSkipped'"" ('False' by default bur default value irrelevant) :
					This output parameter is set to 'True' at each image skipped by the function (if the 'image skipping' feature is activated).
					The user can test it to know if the image is skipped or not ("image skipping" feature working in scrolling mode).
					He can also use this parameter to downright not draw this skipped image at all, allowing for example even higher FPS ("image skipping" feature working in removing mode).
					
	File to be included: "regulateLite.bi"
	{{fbdoc item="filename" value="examples/manual/proguide/graphics/regulateLite.bi"}}%%(freebasic)
' regulateLite.bi

Function regulateLite(ByVal MyFps As Ulong, ByVal SkipImage As Boolean = True, ByVal Restart As Boolean = False, ByRef ImageSkipped As Boolean = False) As Ulong
	'' 'MyFps' : requested FPS value, in frames per second
	'' 'SkipImage' : optional parameter to activate the image skipping (True by default)
	'' 'Restart' : optional parameter to force the resolution acquisition, to reset to False on the next call (False by default)
	'' 'ImageSkipped' : optional parameter to inform the user that the image has been skipped (if image skipping is activated)
	'' function return : applied FPS value (true or apparent), in frames per second
	Static As Single tos
	Static As Single bias
	Static As Long count
	Static As Single sum
	' initialization calibration
	If tos = 0 Or Restart = True Then
		Dim As Double t = Timer
		For I As Integer = 1 To 10
			Sleep 1, 1
		Next I
		Dim As Double tt = Timer
		#if Not defined(__FB_WIN32__) And Not defined(__FB_LINUX__)
		If tt < t Then t -= 24 * 60 * 60
		#endif
		tos = (tt - t) / 10 * 1000
		bias = 0
		count = 0
		sum = 0
	End If
	Static As Double t1
	Static As Long N = 1
	Static As Ulong fps
	Static As Single tf
	' delay generation
	Dim As Double t2 = Timer
	#if Not defined(__FB_WIN32__) And Not defined(__FB_LINUX__)
	If t2 < t1 Then t1 -= 24 * 60 * 60
	#endif
	Dim As Double t3 = t2
	Dim As Single dt = (N * tf - (t2 - t1)) * 1000 - bias
	If (dt >= 3 * tos / 2) Or (SkipImage = False) Or (N >= 20) Or (fps / N <= 10) Then
		If dt <= tos Then dt = tos / 2
		Sleep dt, 1
		t2 = Timer
		#if Not defined(__FB_WIN32__) And Not defined(__FB_LINUX__)
		If t2 < t1 Then t1 -= 24 * 60 * 60 : t3 -= 24 * 60 * 60
		#endif
		fps = N / (t2 - t1)
		tf = 1 / MyFps
		t1 = t2
		' automatic test and regulation
		Dim As Single delta = (t2 - t3) * 1000 - (dt + bias)
		If Abs(delta) > 3 * tos Then
			tos = 0
		Else
			bias += 0.1 * Sgn(delta)
		End If
		' automatic calibation
		If dt < tos Then
			If count = 100 Then
				tos = sum / 100 * 1000
				bias = 0
				sum = 0
				count = 0
			Else
				sum += (t2 - t3)
				count += 1
			End If
		End If
		ImageSkipped = False
		N = 1
	Else
		ImageSkipped = True
		N += 1
	End If
	Return fps
End Function
%%
	__Maximum performance estimation__
		Simple modeling of the user loop and its environment:
				**""-""** tt : execution time of the tracing task
				**""-""** tc : execution time of the calculation task (+ other process)
				**""-""** tm : time of the minimum delay generated by 'regulateLite()' (depending on the OS cycle period) = 16 ms (for Windows in normal resolution)
				**""-""** fm = minimum frequency of the true FPS authorized by 'regulateLite()' in case of 'image skipping' = 10 Hz (fixed in the code)
				**""-""** siM = maximum number of skipped images + 1 = 20 (fixed in the code)
				
		This estimate neglects the execution time of 'regulateLite()' except obviously the delay ('tm') it generates.
		
		Without 'image skipping':
			FPSmax = 1 / (tt + tc + tm)
			
		With 'image skipping' alone (skipped images scrolled):
			k0 = Int((1 / fm - tm) / (tt + tc))
			k = Iif(k0 < siM, k0, siM)
			apparent FPSmax = Cint(1 / (k * (tt + tc) + tm) * k)
			('k' value corresponds to the number of 'skipped images' + 1 : 'k - 1' skipped images over 'k')
			
		With 'image skipping' + skipped images removed by user:
			k0 = Int((1 / fm - tm - tt) / tc)
			k = Iif(k0 < siM, k0, siM)
			apparent FPSmax = Cint(1 / (k * tc + tt + tm) * k)
			('k' value corresponds to the number of 'skipped images' + 1 : 'k - 1' skipped images over 'k')
			
		To highlight the maximum accessible FPS values with 'regulateLite()', depending on the duration of the 2 tasks in the user loop (tracing task and calculation task (+ other process)), a complete table of estimated values is below provided (duration of the 2 tasks ranging from 1 ms to 9 ms each in steps of 1 ms, Windows in normal resolution):
		 %%
'' Constant tm = 0.016 : time of the minimum delay generated by 'regulateLite()' (depending on the OS cycle period)
'' Constant fm = 10    : minimum frequence of the true FPS authorized by 'regulateLite()' in case of 'image skipping'
'' Constant siM = 20   : maximum number of skipped images + 1

'' Variable tt : execution time of the tracing task
'' Variable tc : execution time of the calculation task (+ other process)

'' For each couple (tt,tc) of values, 3 FPS max are estimated, and for each the quota of 'skipped images':
''    - FPS without 'image skipping'                                         , number of 'skipped images' (always '0')
''    - Apparent FPS with 'image skipping' ('skipped images' only scrolled)  , quota of 'skipped images' (only scrolled)
''    - Apparent FPS with 'image skipping' + 'skipped images' removed by user, quota of 'skipped images' removed by user

''           | tt = 1 ms | tt = 2 ms | tt = 3 ms | tt = 4 ms | tt = 5 ms | tt = 6 ms | tt = 7 ms | tt = 8 ms | tt = 9 ms |
'' ----------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|
''           |  56 0     |  53 0     |  50 0     |  48 0     |  45 0     |  43 0     |  42 0     |  40 0     |  38 0     |
'' tc = 1 ms | 357 19/20 | 263 19/20 | 208 19/20 | 167 15/16 | 140 13/14 | 120 11/12 | 104 9/10  |  93 8/9   |  83 7/8   |
''           | 541 19/20 | 526 19/20 | 513 19/20 | 500 19/20 | 488 19/20 | 476 19/20 | 465 19/20 | 455 19/20 | 444 19/20 |
'' ----------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|
''           |  53 0     |  50 0     |  48 0     |  45 0     |  43 0     |  42 0     |  40 0     |  38 0     |  37 0     |
'' tc = 2 ms | 263 19/20 | 208 19/20 | 167 15/16 | 140 13/14 | 120 11/12 | 104 9/10  |  93 8/9   |  83 7/8   |  75 6/7   |
''           | 351 19/20 | 345 19/20 | 339 19/20 | 333 19/20 | 328 19/20 | 323 19/20 | 317 19/20 | 312 19/20 | 308 19/20 |
'' ----------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|
''           |  50 0     |  48 0     |  45 0     |  43 0     |  42 0     |  40 0     |  38 0     |  37 0     |  36 0     |
'' tc = 3 ms | 208 19/20 | 167 15/16 | 140 13/14 | 120 11/12 | 104 9/10  |  93 8/9   |  83 6/7   |  75 6/7   |  70 6/7   |
''           | 260 19/20 | 256 19/20 | 253 19/20 | 250 19/20 | 247 19/20 | 244 19/20 | 241 19/20 | 238 19/20 | 235 19/20 |
'' ----------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|
''           |  48 0     |  45 0     |  43 0     |  42 0     |  40 0     |  38 0     |  37 0     |  36 0     |  34 0     |
'' tc = 4 ms | 167 15/16 | 140 13/14 | 120 11/12 | 104 9/10  |  93 8/9   |  83 7/8   |  75 6/7   |  70 6/7   |  64 5/6   |
''           | 206 19/20 | 204 19/20 | 202 19/20 | 200 19/20 | 196 18/19 | 194 18/19 | 192 18/19 | 190 18/19 | 186 17/18 |
'' ----------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|
''           |  45 0     |  43 0     |  42 0     |  40 0     |  38 0     |  37 0     |  36 0     |  34 0     |  33 0     |
'' tc = 5 ms | 140 13/14 | 120 11/12 | 104 9/10  |  93 8/9   |  83 7/8   |  75 6/7   |  70 6/7   |  64 5/6   |  60 5/6   |
''           | 165 15/16 | 163 15/16 | 162 15/16 | 160 15/16 | 156 14/15 | 155 14/15 | 153 14/15 | 152 14/15 | 150 14/15 |
'' ----------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|
''           |  43 0     |  42 0     |  40 0     |  38 0     |  37 0     |  36 0     |  34 0     |  33 0     |  32 0     |
'' tc = 6 ms | 120 11/12 | 104 9/10  |  93 8/9   |  83 7/8   |  75 6/7   |  70 6/7   |  64 5/6   |  60 5/6   |  55 4/5   |
''           | 137 12/13 | 135 12/13 | 134 12/13 | 133 12/13 | 131 12/13 | 130 12/13 | 126 11/12 | 125 11/12 | 124 11/12 |
'' ----------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|
''           |  42 0     |  40 0     |  38 0     |  37 0     |  36 0     |  34 0     |  33 0     |  32 0     |  31 0     |
'' tc = 7 ms | 104 9/10  |  98 8/9   |  83 7/8   |  75 6/7   |  70 6/7   |  64 5/6   |  60 5/6   |  55 4/5   |  52 4/5   |
''           | 117 10/11 | 116 10/11 | 115 10/11 | 113 10/11 | 112 10/11 | 111 10/11 | 110 10/11 | 106 9/10  | 105 9/10  |
'' ----------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|
''           |  40 0     |  38 0     |  37 0     |  36 0     |  34 0     |  33 0     |  32 0     |  31 0     |  30 0     |
'' tc = 8 ms |  93 8/9   |  83 7/8   |  75 6/7   |  70 6/7   |  64 5/6   |  60 5/6   |  55 4/5   |  52 4/5   |  48 3/4   |
''           | 103 9/10  | 102 9/10  | 101 9/10  | 100 9/10  |  97 8/9   |  96 8/9   |  95 8/9   |  94 8/9   |  93 8/9   |
'' ----------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|
''           |  38 0     |  37 0     |  36 0     |  34 0     |  33 0     |  32 0     |  31 0     |  30 0     |  29 0     |
'' tc = 9 ms |  83 7/8   |  75 6/7   |  70 6/7   |  64 5/6   |  55 5/6   |  55 4/5   |  52 4/5   |  48 3/4   |  45 3/4   |
''           |  92 8/9   |  91 8/9   |  90 8/9   |  87 7/8   |  86 7/8   |  85 7/8   |  84 7/8   |  83 7/8   |  82 7/8   |
'' -----------------------------------------------------------------------------------------------------------------------
%%

{{fbdoc item="section" value="3. Examples of test code"}}
	4 code examples for testing the behavior of the 'regulateLite()' function.
	
	__Test code for simple use of 'regulateLite()'__
		The 'regulateLite()' function is called as a sub (ignoring the return value) and only the mandatory parameter (""'MyFps'"") is used.
		=> "image skipping" feature working in scrolling mode.
		
		The dynamic part of the display consists of the value of the requested FPS and a graphic progress bar to judge the quality of the regulation.
		
		The static part of the display is the list of available commands:
				**""-""** <+/-> for increase/decrease FPS
				**""-""** <escape> to Quit
				
		Test code 1:
		{{fbdoc item="filename" value="examples/manual/proguide/graphics/regulateLite_testCode1.bas"}}%%(freebasic)
#include "regulateLite.bi"

Screen 12
Dim As Ulong FPS = 100
Do
	Static As ULongInt l
	ScreenLock
	Cls
	Color 15
	Print Using "Requested FPS : ###"; FPS
	Print
	Print
	Print
	Color 14
	Print "<+>      : Increase FPS"
	Print "<->      : Decrease FPS"
	Print
	Print "<Escape> : Quit"
	Line (0, 32)-(639, 48), 7, B
	Line (0, 32)-(l, 48), 7, BF
	ScreenUnlock
	l = (l + 1) Mod 640
	Dim As String s = Inkey
	Select Case s
	Case "+"
		If FPS < 200 Then FPS += 1
	Case "-"
		If FPS > 10 Then FPS -= 1
	Case Chr(27)
		Exit Do
	End Select
	regulateLite(FPS)
Loop
%%
	__Test code for improved use of 'regulateLite()'__
		Compared to 'Code for simple test', this code calls 'regulateLite()' as a function and displays the applied FPS (return value).
		Additionally, this code uses the optional ""'ImageSkipped'"" parameter to not display images tagged ""'ImageSkipped=True'"" at all, and also specify the quantum of images displayed.
		=> "image skipping" feature working in removing mode.
		
		Test code 2:
		{{fbdoc item="filename" value="examples/manual/proguide/graphics/regulateLite_testCode2.bas"}}%%(freebasic)
#include "regulateLite.bi"

Screen 12
Dim As Ulong FPS = 100
Do
	Static As ULongInt l
	Static As Ulong MyFPS
	Static As Boolean ImageSkipped
	Static As Long nis
	Static As Long tnis
	If ImageSkipped = False Then
		ScreenLock
		Cls
		Color 15
		Print Using "Requested FPS   : ###"; FPS
		Print
		Color 11
		Print Using "Applied FPS        : ###"; MyFPS
		Print "   Image displayed : 1/" & tnis + 1
		Print
		Print
		Print
		Color 14
		Print "<+>      : Increase FPS"
		Print "<->      : Decrease FPS"
		Print
		Print "<Escape> : Quit"
		Line (0, 80)-(639, 96), 7, B
		Line (0, 80)-(l, 96), 7, BF
		ScreenUnlock
	End If
	l = (l + 1) Mod 640
	Dim As String s = Inkey
	Select Case s
	Case "+"
		If FPS < 200 Then FPS += 1
	Case "-"
		If FPS > 10 Then FPS -= 1
	Case Chr(27)
		Exit Do
	End Select
	MyFPS = regulateLite(FPS, , , ImageSkipped)
	If ImageSkipped = True Then
		nis += 1
	Else
		tnis = nis
		nis = 0
	End If
Loop
%%
	__Test code for intensive use of 'regulateLite()'__
		Compared to 'Code for improved test', this code additionally uses the other two optional parameters ""'SkipImage'"" and 'Restart'.
		This code is used to test all the combinations of the parameters of the function as well as the type of display of the skipped images (either scrolling of the skipped images, or removing of the skipped images).
		("image skipping" feature activated and pre-selected in scrolling mode)
		
		For the Windows platform only, this code allows to change the OS cycle resolution (normal or high) and commands a new calibration phase at each change of resolution.
		
		Added commands:
				**""-""** <T/F> for True/False for image skipping
				**""-""** <S/R> for Scroll/Remove image skipped
				**""-""** <C> for Calibration phase
				**""-""** <N/H> for Normal/High resolution (for Windows platform only)
				
		Test code 3:
		{{fbdoc item="filename" value="examples/manual/proguide/graphics/regulateLite_testCode3.bas"}}%%(freebasic)
#include "regulateLite.bi"

#if defined(__FB_WIN32__)
Declare Function _setTimer Lib "winmm" Alias "timeBeginPeriod"(ByVal As Ulong = 1) As Long
Declare Function _resetTimer Lib "winmm" Alias "timeEndPeriod"(ByVal As Ulong = 1) As Long
#endif

Screen 12, , 2
Screenset 1, 0

Dim As Ulongint MyFps = 100
	
Dim As String res = "N"
Dim As Boolean SkipImage = True
Dim As Boolean Restart = False
Dim As Boolean RemoveImageSkipped = False

Do
	Static As Ulongint l
	Static As Double dt
	Static As Ulong fps
	Static As Double t
	Static As Ulong averageFps
	Static As Double sumFps
	Static As Double averageDelay
	Static As Double sumDelay
	Static As Long N
	Static As Boolean ImageSkipped
	Static As Long ist = 0
	Static As Long mist = 0
	Dim As Double t1
	Dim As Double t2
	If (RemoveImageSkipped = False) OR (ImageSkipped = False) Then
		t = Timer
		Cls
		Print
		Color 15
		Select Case res
		Case "N"
			Print "                      NORMAL RESOLUTION"
		Case "H"
			Print "                      HIGH RESOLUTION (for Windows only)"
		End Select
		Print
		Print " Procedure : regulateLite( "; MyFPS & " [, " & SkipImage & " ])";
		If SkipImage = True Then
			Select Case RemoveImageSkipped
			Case True
				Print "      Images skipped : Removing"
			Case False
				Print "      Images skipped : Scrolling"
			End Select
		Else
				Print "     No image skipping"
		End If
		Print
		Color 11
		If mist = 0 Then
			Print Using " Applied true FPS     : ###         (average : ###)"; fps; averageFps
			Print Using "    Applied delay     : ###.### ms  (average : ###.### ms)"; dt; averageDelay;
		Else
			Print Using " Applied apparent FPS : ###         (average : ###)"; fps; averageFps
			Print Using "    Applied delay     : ###.### ms  (average : ###.### ms)"; dt; averageDelay;
		End If
		If SkipImage = True Then
			Print "  (not skipped image)"
		Else
			Print
		End If
		If SkipImage = True Then
			Select Case RemoveImageSkipped
			Case True
				Print "    Images removed    :  " & Iif(mist > 0, str(mist) & "/" & str(mist + 1), "0")
			Case False
				Print "    Images scrolled   :  " & Iif(mist > 0, str(mist) & "/" & str(mist + 1), "0")
			End Select
		Else
				Print "    No image skipped"
		End If
		Print
		Print
		Print
		Color 14
		#if defined(__FB_WIN32__)
		Print " <n> or <N> : Normal resolution"
		Print " <h> or <H> : High resolutiion"
		Print
		#endif
		Print " <+>        : Increase FPS"
		Print " <->        : Decrease FPS"
		Print
		Print " Optional parameter :"
		Print "    <t> or <T> : True for image skipping"
		If SkipImage = True Then
			Print "        <r> or <R> : Remove image skipped"
			Print "        <s> or <S> : Scroll image skipped"
		End If
		Print "    <f> or <F> : False for image skipping"
		Print "    <c> or <C> : Calibration phase"
		Print
		Print " <escape>   : Quit"
		Line (8, 144)-(631, 160), 7, B
		Line (8, 144)-(8 + l, 160), 7, BF
		Do
		#if Not defined(__FB_WIN32__) And Not defined(__FB_LINUX__)
			t2 = Timer
			If t2 < t Then t -= 24 * 60 * 60
		Loop Until t2 >= t + 0.002
		#else
		Loop Until Timer >= t + 0.002
		#endif
		Screencopy
	End If
	l = (l + 1) Mod 624
	Dim As String s = Ucase(Inkey)
	Select Case s
	Case "+"
		If MyFPS < 500 Then MyFPS += 1
	Case "-"
		If MyFPS > 10 Then MyFPS -= 1
	Case "T"
		SkipImage = True
	Case "F"
		SkipImage = False
	#if defined(__FB_WIN32__)
	Case "N"
		If res = "H" Then
			Restart = True
			res = "N"
		End If
	Case "H"
		If res = "N" Then
			Restart = True
			res = "H"
		End If
	#endif
	Case "C"
		Restart = True
	Case "R"
		If SkipImage = True Then RemoveImageSkipped = True
	Case "S"
		If SkipImage = True Then RemoveImageSkipped = False
	Case Chr(27)
		Exit Do
	End Select
	sumFps += fps
	sumDelay += dt
	N += 1
	If N >= fps / 2 Then
		averageFps = sumFps / N
		averageDelay = sumDelay / N
		N = 0
		sumFps = 0
		sumDelay = 0
	End If
	#if defined(__FB_WIN32__)
	If res = "H" Then
		_setTimer()
	End If
	#endif
	t1 = Timer
	fps = regulateLite(MyFPS, SkipImage, Restart, ImageSkipped)
	If ImageSkipped = False Then
		t2 = Timer
		#if Not defined(__FB_WIN32__) And Not defined(__FB_LINUX__)
		If t2 < t1 Then t1 -= 24 * 60 * 60
		#endif
		dt = (t2 - t1) * 1000
	End If
	#if defined(__FB_WIN32__)
	If res = "H" Then
		_resetTimer()
	End If
	#endif
	Restart = False
	If ImageSkipped = True Then
		ist += 1
	Else
		mist = ist
		ist = 0
	End If
Loop
%%	
	__Test code for maximum performance emulation of 'regulateLite()'__
		Consider following notations:
				**""-""** tt : execution time of the user tracing task
				**""-""** tc : execution time of the user calculation task (+ other process)
				
		An emulation code is written with two TIMER waiting loops (for 'tt' and 'tc'), and calling the real 'regulateLite()', which allows to estimate the magnitude order of the maximum accessible performance.
		This emulation allows to validate the order of magnitude of the results from the 'Maximum performance estimation' paragraph above.
		
		Use the runtime commands to adjust the 'tt' and 'tc' values and test the 3 configurations using the optional parameters.
		This test code works with the resolution from the OS cycle.
		
		Test code 4:
		{{fbdoc item="filename" value="examples/manual/proguide/graphics/regulateLite_testCode4.bas"}}%%(freebasic)
Dim As Integer tt = 10  ' (in milliseconds)
Dim As Integer tc =  5  ' (in milliseconds)

#include "regulateLite.bi"

Screen 12, , 2
Screenset 1, 0

Dim As Ulongint MyFps = 9999
	
Dim As String res = "N"
Dim As Boolean SkipImage = False
Dim As Boolean RemoveImageSkipped = False

Do
	Static As Ulong fps
	Static As Ulong averageFps
	Static As Double sumFps
	Static As Long N
	Static As Boolean ImageSkipped
	Static As Long ist = 0
	Static As Long mist = 0
	Static As ULongInt l
	Dim As Double t1
	Dim As Double t2
	If (RemoveImageSkipped = False) OR (ImageSkipped = False) Then
		t1 = Timer
		Cls
		Print
		Color 15
		Print "          MAXIMUM PERFORMANCE EMULATION of 'regulateLite()' regulation"
		Print
		Print
		Print Using " tt = ## ms   (execution time of the tracing task)"; tt
		Print Using " tc = ## ms   (execution time of the calculation task + other process)"; tc
		Print
		Print " Procedure : regulateLite( "; MyFPS & " [, " & SkipImage & " ])";
		If SkipImage = True Then
			Select Case RemoveImageSkipped
			Case True
				Print "      Images skipped : Removing"
			Case False
				Print "      Images skipped : Scrolling"
			End Select
		Else
				Print "     No image skipping"
		End If
		Print
		Print
		Color 11
		If mist = 0 Then
			Print Using " Applied true FPS max     :####         (average :####)"; fps; averageFps
		Else
			Print Using " Applied apparent FPS max :####         (average :####)"; fps; averageFps
		End If
		If SkipImage = True Then
			Select Case RemoveImageSkipped
			Case True
				Print "    Images removed        :  " & Iif(mist > 0, str(mist) & "/" & str(mist + 1), "0")
			Case False
				Print "    Images scrolled       :  " & Iif(mist > 0, str(mist) & "/" & str(mist + 1), "0")
			End Select
		Else
				Print "    No image skipped"
		End If
		Print
		Print
		Color 14
		Print " <+>        : Increment tt"
		Print " <->        : Decrement tt"
		Print
		Print " <i> or <I> : Increment tc"
		Print " <d> or <D> : Decrement tc"
		Print
		Print " Optional parameter :"
		Print "    <t> or <T> : True for image skipping"
		If SkipImage = True Then
			Print "        <r> or <R> : Remove image skipped"
			Print "        <s> or <S> : Scroll image skipped"
		End If
		Print "    <f> or <F> : False for image skipping"
		Print
		Print " <escape>   : Quit"
		Line (0, 197)-(639, 199), 3, B
		Line (0, 198)-(l, 198), 11
		Do
		#if Not defined(__FB_WIN32__) And Not defined(__FB_LINUX__)
			t2 = Timer
			If t2 < t Then t -= 24 * 60 * 60
		Loop Until t2 >= t1 + tt / 1000
		#else
		Loop Until Timer >= t1 + tt / 1000
		#endif
		Screencopy
	End If
	t1 = Timer
	Dim As String s = Ucase(Inkey)
	Select Case s
	Case "+"
		If tt < 30 Then tt += 1
	Case "-"
		If tt > 1 Then tt -= 1
	Case "I"
		If tc < 30 Then tc += 1
	Case "D"
		If tc > 1 Then tc -= 1
	Case "T"
		SkipImage = True
	Case "F"
		SkipImage = False
	Case "R"
		If SkipImage = True Then RemoveImageSkipped = True
	Case "S"
		If SkipImage = True Then RemoveImageSkipped = False
	Case Chr(27)
		Exit Do
	End Select
	sumFps += fps
	N += 1
	If N >= fps / 2 Then
		averageFps = sumFps / N
		N = 0
		sumFps = 0
	End If
	If ImageSkipped = True Then
		ist += 1
	Else
		mist = ist
		ist = 0
	End If
	l = (l + 1) Mod 640
	Do
	#if Not defined(__FB_WIN32__) And Not defined(__FB_LINUX__)
		t2 = Timer
		If t2 < t Then t -= 24 * 60 * 60
	Loop Until t2 >= t1 + tc / 1000
	#else
	Loop Until Timer >= t1 + tc / 1000
	#endif
	fps = regulateLite(MyFPS, SkipImage, , ImageSkipped)
Loop
%%		**Note:** As the applied FPS is at maximum limit, 'regulateLite()' periodically refreshes the value of tm (calibration at runtime), so the FPS values found can shift at each new calibration (slow rate).

{{fbdoc item="section" value="4. Examples of graphic animation code"}}
	These two graphic animations highlight the interest of the image skipping feature of 'regulateLite()', with scrolling and above all removing of skipped images.
	
	__Graphic animation 1__
		This graphic animation (heavy CPU load) comes from **dodicat** ([[https://www.freebasic.net/forum/viewtopic.php?p=184009#p184009]]).
		Some initializations and code lines may have been modified from the author's original in order to better highlight the regulation with 'regulateLite()' and its different configurations of use.
		
		This code allows to modify:
				**""-""** the value of the requested FPS (and it visualizes the applied FPS),
				**""-""** the image skipping activation (false or true),
				**""-""** and in case of image skipping activated, the mode for skipping images (scrolling or removing).
				(the removing skipped images adds only three lines to the user code)
				The full status of the image skipping feature is also visualized.
				
		Graphic animation code 1:
		{{fbdoc item="filename" value="examples/manual/proguide/graphics/regulateLite_animationCode.bas"}}%%(freebasic)
'' Graphic animation from dodicat (https://www.freebasic.net/forum/viewtopic.php?p=184009#p184009)

#include "regulateLite.bi"

Type vector3d
	As Single x,y,z
End Type
'assignment macro
#define vct Type<vector3d>
 
 'macros
	#define map(a,b,x,c,d) ((d)-(c))*((x)-(a))/((b)-(a))+(c)
	#macro combsort(array,begin,finish,dot)
	Scope
		Var size=(finish),switch=0,j=0
		Dim As Single void=size
		Do
			void=void/1.3: If void<1 Then void=1
			switch=0
			For i As Integer =(begin) To size-void
				j=i+void
				If array(i)dot<array(j)dot Then 
					Swap array(i),array(j): switch=1
				End If
			Next
		Loop Until  switch =0 And void=1
	End Scope
	#endmacro
	
	Operator -(Byref v1 As vector3d,Byref v2 As vector3d) As vector3d
		Return Type<vector3d>(v1.x-v2.x,v1.y-v2.y,v1.z-v2.z)
	End Operator
	
	Operator + (Byref v1 As vector3d,Byref v2 As vector3d) As vector3d
	Return Type<vector3d>(v1.x+v2.x,v1.y+v2.y,v1.z+v2.z)
	End Operator
	
	Function length(Byref v1 As vector3d) As Single
		Return Sqr(v1.x*v1.x+v1.y*v1.y+v1.z*v1.z)
	End Function 
	
	Function rotate3d(Byval pivot As vector3d,Byval pt As vector3d,Byval Angle As vector3d, Byval scale As vector3d=Type<vector3d>(1,1,1)) As vector3d
		#define cr 0.0174532925199433
		Angle=Type<vector3d>(Angle.x*cr,Angle.y*cr,Angle.z*cr)
		#macro Rotate(a1,a2,b1,b2,d)
		temp=Type<vector3d>((a1)*Cos(Angle.d)+(a2)*Sin(Angle.d),(b1)*Cos(Angle.d)+(b2)*Sin(Angle.d))
		#endmacro
		Dim As vector3d p=Type<vector3d>(pt.x-pivot.x,pt.y-pivot.y,pt.z-pivot.z)
		Dim As vector3d rot,temp
		Rotate(p.y,-p.z,p.z,p.y,x)'X
		rot.y=temp.x:rot.z=temp.y 
		p.y = rot.y:p.z = rot.z 
		Rotate(p.z,-p.x,p.x,p.z,y)'Y
		rot.z=temp.x:rot.x=temp.y
		p.x=rot.x
		Rotate(p.x,-p.y,p.y,p.x,z)'Z
		rot.x=temp.x:rot.y=temp.y
		Return Type<vector3d>((scale.x*rot.x+pivot.x),(scale.y*rot.y+pivot.y),(scale.z*rot.z+pivot.z))
	End Function
	
	Function apply_perspective(Byref p As vector3d,Byref eyepoint As vector3d) As vector3d
		Dim As Single   w=1+(p.z/eyepoint.z)
		If w=0 Then w=1e-20
		Return Type<vector3d>((p.x-eyepoint.x)/w+eyepoint.x,(p.y-eyepoint.y)/w+eyepoint.y,(p.z-eyepoint.z)/w+eyepoint.z)
	End Function
	'====================== End of rotator and perspective getter ======================================
	Dim Shared As Integer xres,yres
	Screenres 800, 640, 8
	Width 800 \ 8, 640 \ 16
	Screeninfo xres,yres

	'two main arrays
	Dim Shared As vector3d rotated()
	Redim Shared As vector3d array()
	'extra subs to regulate speed
	'four shapes
	Function create1(Byval number As Integer) As Integer
		Redim array(0)
		Dim As Integer count,stepper=10
		For x As Integer=xres/2-number To xres/2+number Step stepper
			For y As Integer=yres/2-number To yres/2+number Step stepper
				For z As Integer=-number To number Step stepper
					count=count+1
					Redim Preserve array(1 To count)
					array(Ubound(array))=vct(x,y,z)
				Next z
			Next y
		Next x
		Redim rotated(Lbound(array) To Ubound(array))
		Return 0
	End Function
	
	'variables
	Dim As vector3d centre=vct(xres/2,yres/2,0)
	Dim As vector3d eyepoint=vct(xres/2,yres/2,600)
	Dim As vector3d angle
	Dim As Long fps=150,rfps
	Dim As Boolean skipping=False,remove=False,skipped
	Dim As Long ist,mist
	Dim As Ulong averageFps
	Dim As Double sumFps
	Dim As Long N
	Dim As vector3d disp=vct(xres/2,yres/2,0)
	Dim As Integer k,flag=1,border=.2*xres
	Dim As Single sx=1,kx=2,ky=1.9,kz=1.5
	create1(90)
	Do
		angle=angle+vct(.2,2,.1)
		With angle
			If .x>=360 Then .x-=360
			If .y>=360 Then .y-=360
			If .x>=360 Then .z-=360
		End With
		disp=disp+vct(kx,ky,0)
		If disp.x<border Then kx=-kx
		If disp.x>xres-border Then kx=-kx
		If disp.y<border Then ky=-ky
		If disp.y>yres-border Then ky=-ky
		If (remove = False) Or (skipped = False) Then
			Screenlock
			Cls
			
			For n As Integer=1 To Ubound(rotated)
				rotated(n)=rotate3d(centre,(array(n)),angle,vct(sx,sx,sx))
			Next n
			
			combsort(rotated,1,Ubound(rotated),.z)
			
			For n As Integer=1 To Ubound(rotated)
				Var dist=length(rotated(n)-centre)
				rotated(n)=apply_perspective(rotated(n),eyepoint)
				rotated(n)=rotated(n)+(disp-centre)
				
				Var col=map(0,200,dist,1,15)
				Var radius=map(-400,400,rotated(n).z,10,1)
				Circle (rotated(n).x,rotated(n).y),radius,col,,,,f
			Next n
			
			Draw String (16,16),"Requested FPS = " & Right("  " & fps, 3)
			Draw String (16,32),"Applied FPS   = " & Right("  " & rfps, 3) & "   (average = " & Right("  " & averageFps, 3) & ")"
			Draw String (16,48),"Status : " & _
				iif(skipping = True, "Image skipping activation = true, with " & _
				iif(remove = True, "removing images skipped = " & Iif(mist > 0, str(mist) & "/" & str(mist + 1), "0"), _
				"scrolling images skipped = " & Iif(mist > 0, str(mist) & "/" & str(mist + 1), "0")), _
				"Image skipping activation = false")
			Draw String (16,80),"<+> : Increase FPS"
			Draw String (16,96),"<-> : Decrease FPS"
			Draw String (16,128),"<t> or <T> : True for image skipping activation"
			If Skipping = True Then
				Draw String (16,144),"   <s> or <S> : Scroll image skipped"
				Draw String (16,160),"   <r> or <R> : Remove image skipped"
				Draw String (16,176),"<f> or <F> : False for image skipping activation"
				Draw String (16,208),"<escape> : Quit"
			Else
				Draw String (16,144),"<f> or <F> : False for image skipping activation"
				Draw String (16,176),"<escape> : Quit"
			End If
			Draw String (544,608),"Graphic animation from dodicat"
			Screenunlock
		End If
		rfps = regulateLite(fps,skipping, ,skipped)
		If skipped = True Then
			ist += 1
		Else
			mist = ist
			ist = 0
		End If
		sumFps += rfps
		N += 1
		If N >= rfps / 2 Then
			averageFps = sumFps / N
			N = 0
			sumFps = 0
		End If
		Dim As String s = Ucase(Inkey)
		Select Case s
		Case "+"
			If fps < 700 Then fps += 1
		Case "-"
			If fps > 10 Then fps -= 1
		Case "T"
			skipping = True
		Case "F"
			skipping = False
		Case "S"
			If skipping = True Then remove = False
		Case "R"
			If skipping = True Then remove = True
		Case Chr(27)
			Exit do
		End Select
	Loop
%%

	__Graphic animation 2__
		This graphic animation (heavy CPU load) comes from **dodicat** ([[https://www.freebasic.net/forum/viewtopic.php?p=195122#p195122]]).
		Some initializations and code lines may have been modified from the author's original in order to better highlight the regulation with 'regulateLite()' and its different configurations of use.
		
		This code allows to modify:
				**""-""** the value of the requested FPS (and it visualizes the applied FPS),
				**""-""** the image skipping activation (false or true),
				**""-""** and in case of image skipping activated, the mode for skipping images (scrolling or removing).
				(the removing skipped images adds only three lines to the user code)
				The full status of the image skipping feature is also visualized.
				
		Graphic animation code 2:
		{{fbdoc item="filename" value="examples/manual/proguide/graphics/regulateLite_animationCode2.bas"}}%%(freebasic)
'' Graphic animation from dodicat (https://www.freebasic.net/forum/viewtopic.php?p=195122#p195122)

#include "regulateLite.bi"

Sub Thing(Byval w As Integer=700, _
	Byval h As Integer=600, _
	Byval posx As Integer=400, _
	Byval posy As Integer=300, _
	Byval morph as single=24, _
	Byval aspect as single=3, _
	Byval grade as single=6, _
	Byval col as uinteger=rgba(255,255,255,0))
		  
	Dim As Single XStep = 1
	Dim As Single YStep = 1
	Dim As Single b=w*w
	Dim As Single y,m,n
	For x As Single = 0 To w Step XStep
		dim as single s=x*x
		dim as single p=Sqr(b-s)
		For i As Single = -P To P Step grade*YStep
			dim as single r = Sqr(s+i*i)/w
			dim as single Q = (R - 1) * Sin(morph*r)
			y=i/aspect+q*h
			If i = -p Then m=y:n=y
			If y > m Then m = y
			If y < n Then n = y
			If m=y Orelse n=y Then
				Pset(x/2+posx,-Y/2+posy),col/i 
				Pset(-x/2+posx,-Y/2+posy),col/i
			End If
		Next
	Next
End Sub

'===========================================================

Screenres 800, 640, 32, 2
Width 800 \ 8, 640 \ 16
color,rgb(0,0,50)
screenset 1,0

Dim As single Morph=0,k=1
dim as single aspect,counter,pi2=8*atn(1)
Dim As Long fps=80,rfps
Dim As Boolean skipping=False,remove=False,skipped
Dim As Long ist,mist
Dim As Ulong averageFps
Dim As Double sumFps
Dim As Long N

Do
	counter+=.1
	if counter>=pi2 then counter=0
	aspect=3+sin(counter)
	Morph+=.1*k
	If Morph>35 Then k=-k
	If Morph<-35 Then k=-k
	If (remove = False) Or (skipped = False) Then
		Cls
		Thing(800,500,400,300,Morph,aspect) 
		Draw String (16,16),"Requested FPS = " & Right("  " & fps, 3)
		Draw String (16,32),"Applied FPS   = " & Right("  " & rfps, 3) & "   (average = " & Right("  " & averageFps, 3) & ")"
		Draw String (16,48),"Status : " & _
			iif(skipping = True, "Image skipping activation = true, with " & _
			iif(remove = True, "removing images skipped = " & Iif(mist > 0, str(mist) & "/" & str(mist + 1), "0"), _
			"scrolling images skipped = " & Iif(mist > 0, str(mist) & "/" & str(mist + 1), "0")), _
			"Image skipping activation = false")
		Draw String (16,80),"<+> : Increase FPS"
		Draw String (16,96),"<-> : Decrease FPS"
		Draw String (16,128),"<t> or <T> : True for image skipping activation"
		If Skipping = True Then
			Draw String (16,144),"   <s> or <S> : Scroll image skipped"
			Draw String (16,160),"   <r> or <R> : Remove image skipped"
			Draw String (16,176),"<f> or <F> : False for image skipping activation"
			Draw String (16,208),"<escape> : Quit"
		Else
			Draw String (16,144),"<f> or <F> : False for image skipping activation"
			Draw String (16,176),"<escape> : Quit"
		End If
		Draw String (544,608),"Graphic animation from dodicat"
		flip
	End If
	rfps = regulateLite(fps,skipping, ,skipped)
	If skipped = True Then
		ist += 1
	Else
		mist = ist
		ist = 0
	End If
	sumFps += rfps
	N += 1
	If N >= rfps / 2 Then
		averageFps = sumFps / N
		N = 0
		sumFps = 0
	End If
	Dim As String s = Ucase(Inkey)
	Select Case s
	Case "+"
		If fps < 600 Then fps += 1
	Case "-"
		If fps > 10 Then fps -= 1
	Case "T"
		skipping = True
	Case "F"
		skipping = False
	Case "S"
		If skipping = True Then remove = False
	Case "R"
		If skipping = True Then remove = True
	Case Chr(27)
		Exit do
	End Select
Loop
%%

	One can notice that for these 2 graphic animations, the mode of operation with 'image skipping' activated plus 'skipped image' removed by the user makes it possible to reach higher FPS, because in these two cases the user code has well separated the drawing part of the new image (the only part that should not be executed when the 'skipped image' tag is true) from the calculation part of the parameters for the new image (which must always be executed).

{{fbdoc item="section" value="See also"}}
	- ##[[KeyPgSleep|Sleep]]##
	- ##[[KeyPgTimer|Timer]]##
	- [[ProPgAntiFlickering|Graphics Mode Refresh and Anti-Flickering]]
	- [[ProPgDelayRegulate|Fine-grain procedure for waiting and in-loop procedure for fine-regulating FPS]]

{{fbdoc item="back" value="CatPgProgrammer|Programmer's Guide"}}