Suite à l'étude du code suivant http://www.purebasic.fr/english/viewtop ... 12&t=43033 voici un système de contrôle fréquentiel d'une boucle. Le système s'adapte et ralenti la boucle de telle manière qu'elle tourne une fréquence très proche de celle demandée (On veut 50 Hz, elle tourne à 49.9 Hz). Puisque l'on travaille dans l'ordre des millisecondes, il difficile de réguler parfaitement la fréquence de la boucle. Le système agit comme un limitateur de vitesse, ce qui implique que si la charge de calcul augmente, la fréquence de la boucle va diminuer et on n'y peut rien mise à part de faire les calculs en parallèles (Threads) ou en massivement parallèles (CUDA + Carte NVIDIA C1060 Tesla).
Dans mon cas je l'utilise afin de réguler la boucle de gestion d'un jeu en 3D, boucle qui comprend la mise à jour du monde 3D, l'IA, le rendu 3D-2D et les évènements (Input Clavier, Souris, Joystick).
A+
Guimauve
Code : Tout sélectionner
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; CODE GÉNÉRÉ AUTOMATIQUEMENT, NE PAS MODIFIER À
; MOINS D'AVOIR UNE RAISON TRÈS TRÈS VALABLE !!!
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; Code généré par : Dev-Type V2.0.1
; Nom du projet : Contrôle fréquentielle d'une boucle
; Nom du fichier : FrameRateControl.pb
; Version du fichier : 1.0.0
; Programmation : OK
; Programmé par : Guimauve
; Date : 15-09-2010
; Mise à jour : 15-09-2010
; Codé pour PureBasic V4.51 RC2
; Plateforme : Windows, Linux, MacOS X
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; <<<<< Constantes de dimensionnement <<<<<
Enumeration
#FRAMERATECONTROL_TIMER_FPS
#FRAMERATECONTROL_TIMER_FLIP
#FRAMERATECONTROL_TIMER_MAX
EndEnumeration
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; <<<<< Déclaration de la Structure <<<<<
Structure FrameRateControl
FpsCounter.l
FpsActual.d
Frequency.l
FrameTime.l
DelayTime.l
CurrentTick.l[#FRAMERATECONTROL_TIMER_MAX]
LastTick.l[#FRAMERATECONTROL_TIMER_MAX]
ElapsedTick.l[#FRAMERATECONTROL_TIMER_MAX]
EndStructure
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<
; <<<<< Les observateurs <<<<<
Macro GetFrameRateControlFpsCounter(FrameRateControlA)
FrameRateControlA\FpsCounter
EndMacro
Macro GetFrameRateControlFpsActual(FrameRateControlA)
FrameRateControlA\FpsActual
EndMacro
Macro GetFrameRateControlFrequency(FrameRateControlA)
FrameRateControlA\Frequency
EndMacro
Macro GetFrameRateControlFrameTime(FrameRateControlA)
FrameRateControlA\FrameTime
EndMacro
Macro GetFrameRateControlDelayTime(FrameRateControlA)
FrameRateControlA\DelayTime
EndMacro
Macro GetFrameRateControlCurrentTick(FrameRateControlA, TimerID)
FrameRateControlA\CurrentTick[TimerID]
EndMacro
Macro GetFrameRateControlLastTick(FrameRateControlA, TimerID)
FrameRateControlA\LastTick[TimerID]
EndMacro
Macro GetFrameRateControlElapsedTick(FrameRateControlA, TimerID)
FrameRateControlA\ElapsedTick[TimerID]
EndMacro
; <<<<<<<<<<<<<<<<<<<<<<<<<
; <<<<< Les mutateurs <<<<<
Macro SetFrameRateControlFpsCounter(FrameRateControlA, P_FpsCounter)
GetFrameRateControlFpsCounter(FrameRateControlA) = P_FpsCounter
EndMacro
Macro SetFrameRateControlFpsActual(FrameRateControlA, P_FpsActual)
GetFrameRateControlFpsActual(FrameRateControlA) = P_FpsActual
EndMacro
Macro SetFrameRateControlFrequency(FrameRateControlA, P_Frequency)
GetFrameRateControlFrequency(FrameRateControlA) = P_Frequency
EndMacro
Macro SetFrameRateControlFrameTime(FrameRateControlA, P_FrameTime)
GetFrameRateControlFrameTime(FrameRateControlA) = P_FrameTime
EndMacro
Macro SetFrameRateControlDelayTime(FrameRateControlA, P_DelayTime)
GetFrameRateControlDelayTime(FrameRateControlA) = P_DelayTime
EndMacro
Macro SetFrameRateControlCurrentTick(FrameRateControlA, TimerID, P_CurrentTick)
GetFrameRateControlCurrentTick(FrameRateControlA, TimerID) = P_CurrentTick
EndMacro
Macro SetFrameRateControlLastTick(FrameRateControlA, TimerID, P_LastTick)
GetFrameRateControlLastTick(FrameRateControlA, TimerID) = P_LastTick
EndMacro
Macro SetFrameRateControlElapsedTick(FrameRateControlA, TimerID, P_ElapsedTick)
GetFrameRateControlElapsedTick(FrameRateControlA, TimerID) = P_ElapsedTick
EndMacro
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; <<<<< L'opérateur Reset <<<<<
Macro ResetFrameRateControl(FrameRateControlA)
SetFrameRateControlFpsCounter(FrameRateControlA, 0)
SetFrameRateControlFpsActual(FrameRateControlA, 0)
SetFrameRateControlFrequency(FrameRateControlA, 0)
SetFrameRateControlFrameTime(FrameRateControlA, 0)
SetFrameRateControlDelayTime(FrameRateControlA, 0)
For TimerID = 0 To #FRAMERATECONTROL_TIMER_MAX - 1
SetFrameRateControlCurrentTick(FrameRateControlA, TimerID, 0)
SetFrameRateControlLastTick(FrameRateControlA, TimerID, 0)
SetFrameRateControlElapsedTick(FrameRateControlA, TimerID, 0)
Next
; ClearStructure(FrameRateControlA, FrameRateControl)
EndMacro
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; <<<<< L'opérateur Initialize <<<<<
Procedure InitializeFrameRateControl(*FrameRateControlA.FrameRateControl, P_Frequency.l)
SetFrameRateControlFpsCounter(*FrameRateControlA, 0)
SetFrameRateControlFpsActual(*FrameRateControlA, 0)
SetFrameRateControlFrequency(*FrameRateControlA, P_Frequency)
SetFrameRateControlFrameTime(*FrameRateControlA, 1000/P_Frequency)
SetFrameRateControlDelayTime(*FrameRateControlA, 0)
For TimerID = 0 To #FRAMERATECONTROL_TIMER_MAX - 1
SetFrameRateControlCurrentTick(*FrameRateControlA, TimerID, 0)
SetFrameRateControlLastTick(*FrameRateControlA, TimerID, 0)
SetFrameRateControlElapsedTick(*FrameRateControlA, TimerID, 0)
Next
EndProcedure
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; <<<<< Code généré en : 00.010 secondes (21000.00 lignes/seconde) <<<<<
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
Procedure StartFrameRateControlTimers(*FrameRateControlA.FrameRateControl)
For TimerID = 0 To #FRAMERATECONTROL_TIMER_MAX - 1
SetFrameRateControlCurrentTick(*FrameRateControlA, TimerID, ElapsedMilliseconds())
SetFrameRateControlLastTick(*FrameRateControlA, TimerID, GetFrameRateControlCurrentTick(*FrameRateControlA, TimerID))
SetFrameRateControlElapsedTick(*FrameRateControlA, TimerID, 0)
Next
EndProcedure
Procedure UpdateFrameRateControlTimerFlip(*FrameRateControlA.FrameRateControl)
SetFrameRateControlCurrentTick(*FrameRateControlA, #FRAMERATECONTROL_TIMER_FLIP, ElapsedMilliseconds())
SetFrameRateControlElapsedTick(*FrameRateControlA, #FRAMERATECONTROL_TIMER_FLIP, GetFrameRateControlCurrentTick(*FrameRateControlA, #FRAMERATECONTROL_TIMER_FLIP) - GetFrameRateControlLastTick(*FrameRateControlA, #FRAMERATECONTROL_TIMER_FLIP))
SetFrameRateControlLastTick(*FrameRateControlA, #FRAMERATECONTROL_TIMER_FLIP, GetFrameRateControlCurrentTick(*FrameRateControlA, #FRAMERATECONTROL_TIMER_FLIP))
SetFrameRateControlFpsCounter(*FrameRateControlA, GetFrameRateControlFpsCounter(*FrameRateControlA) + 1)
EndProcedure
Procedure FrameRateControl_SlowDownIfNeeded(*FrameRateControlA.FrameRateControl)
SetFrameRateControlCurrentTick(*FrameRateControlA, #FRAMERATECONTROL_TIMER_FPS, ElapsedMilliseconds())
SetFrameRateControlElapsedTick(*FrameRateControlA, #FRAMERATECONTROL_TIMER_FPS, GetFrameRateControlCurrentTick(*FrameRateControlA, #FRAMERATECONTROL_TIMER_FPS) - GetFrameRateControlLastTick(*FrameRateControlA, #FRAMERATECONTROL_TIMER_FPS))
If GetFrameRateControlElapsedTick(*FrameRateControlA, #FRAMERATECONTROL_TIMER_FPS) >= 1000
SetFrameRateControlFpsActual(*FrameRateControlA, (GetFrameRateControlFpsCounter(*FrameRateControlA) / GetFrameRateControlElapsedTick(*FrameRateControlA, #FRAMERATECONTROL_TIMER_FPS)) * 1000)
SetFrameRateControlCurrentTick(*FrameRateControlA, #FRAMERATECONTROL_TIMER_FPS, ElapsedMilliseconds())
SetFrameRateControlElapsedTick(*FrameRateControlA, #FRAMERATECONTROL_TIMER_FPS, GetFrameRateControlCurrentTick(*FrameRateControlA, #FRAMERATECONTROL_TIMER_FPS) - GetFrameRateControlLastTick(*FrameRateControlA, #FRAMERATECONTROL_TIMER_FPS))
SetFrameRateControlLastTick(*FrameRateControlA, #FRAMERATECONTROL_TIMER_FPS, GetFrameRateControlCurrentTick(*FrameRateControlA, #FRAMERATECONTROL_TIMER_FPS))
SetFrameRateControlFpsCounter(*FrameRateControlA, 0)
EndIf
SetFrameRateControlCurrentTick(*FrameRateControlA, #FRAMERATECONTROL_TIMER_FLIP, ElapsedMilliseconds())
SetFrameRateControlElapsedTick(*FrameRateControlA, #FRAMERATECONTROL_TIMER_FLIP, GetFrameRateControlCurrentTick(*FrameRateControlA, #FRAMERATECONTROL_TIMER_FLIP) - GetFrameRateControlLastTick(*FrameRateControlA, #FRAMERATECONTROL_TIMER_FLIP))
SetFrameRateControlDelayTime(*FrameRateControlA, GetFrameRateControlFrameTime(*FrameRateControlA) - GetFrameRateControlElapsedTick(*FrameRateControlA, #FRAMERATECONTROL_TIMER_FLIP))
If GetFrameRateControlDelayTime(*FrameRateControlA) >= 1
Delay(GetFrameRateControlDelayTime(*FrameRateControlA))
EndIf
EndProcedure
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; <<<<< !!! WARNING - YOU ARE NOW IN A TESTING ZONE - WARNING !!! <<<<<
; <<<<< !!! WARNING - THIS CODE SHOULD BE COMMENTED - WARNING !!! <<<<<
; <<<<< !!! WARNING - BEFORE THE FINAL COMPILATION. - WARNING !!! <<<<<
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
InitializeFrameRateControl(FrameRateControl.FrameRateControl, 50)
StartFrameRateControlTimers(FrameRateControl)
Repeat
UpdateFrameRateControlTimerFlip(FrameRateControl)
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; <<<<< Début de la section des instructions <<<<<
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; 1. Gestion Évenèments + Clavier, Souris, Joystick
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; 2. Mise à jour de l'espace 3D (Position, Collision)
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; 3. Affichage de l'espace 3D vue par la(les) caméra(s)
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; 4. Affichage des éléments 2D (Messages, menus, etc.)
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; <<<<< Fin de la section des instructions <<<<<
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
FrameRateControl_SlowDownIfNeeded(FrameRateControl)
Debug StrD(GetFrameRateControlFpsActual(FrameRateControl),1) + " FPS"
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; Les instructions suivantes servent uniquement pour terminer la boucle.
; En temps normal, la sortie de la boucle de dépend pas d'un nombre de
; tours de boucle. Elle dépend plutôt d'un évènement particulier.
If LoopCount >= 250
Quit = #True
Else
LoopCount + 1
Debug LoopCount
EndIf
Until Quit = #True
ResetFrameRateControl(FrameRateControl)
; <<<<<<<<<<<<<<<<<<<<<<<<<<
; <<<<< FIN DU FICHIER <<<<<
; <<<<<<<<<<<<<<<<<<<<<<<<<<