Dans la plupart des jeux, il est possible de limiter le nombre d'images par seconde (FPS, frames per second) que peut afficher un jeu.
Il est souvent inutile de gaspiller du temps machine pour afficher jusqu'à 3000 FPS avec des cartes graphiques dernier cri (aaaaaahhh !). L'oeil n'en percoit qu'une centaine au maximum.
Ce programme :
* calcule le nombre de FPS.
* limite le nombre de FPS selon votre choix.
* déplace les objets selon la méthode du TimeStep (déplacement en fonction du temps).
* toutes les valeurs des variables sont affichées en temps réel (toutes les 1s).
Comment faire ?
* Le principal soucis pour calculer le nombre d'images par seconde est de réussir à trouver des fonctions de timing très précises. Les fonctions classiques sont trop imprécises (de l'ordre de 1 à 10 ms). C'est une précision insuffisante lorsqu'on désire afficher plus de 100 FPS (ca nous fait une image toutes les 10ms ou moins). Les seules fonctions intéressantes sont QueryPerformanceFrequency et QueryPerformanceCounter (qui existent bien sur tous les processeurs, quoi qu'en dise la MSDN, qui doit dater un peu). Leur seul inconvénient est de ne pas donner directement le temps, il faut au préalable diviser le nombre de cycle par la fréquence du nombre de cycles par seconde. Il y a donc un coût en temps supplémentaire pour les divisions et également un coût en mémoire pour stocker les résultats en seconde dans des variables de type double.
* Le nombre de cycles est un résultat beaucoup plus précis que le millième de seconde. Un cycle correspond environ (sur mon PC, Barton 3200+) à 270 nano secondes.
* Pour calculer le nombre de frames par seconde (FPS), nous allons comptabiliser toutes les frames affichées (temps.nbFrames). Ensuite, toutes les secondes, on affiche le résultat et on remet le compteur à 0. Le résultat est assez précis.
* Pour limiter le nombre de FPS, il faut 2 variables. Il faut comptabiliser le nombre de cycles maintenant (temps.cSuiv) et le nombre de cycles pour la prochaine frame (temps.cSuiv). Dès que temps.cNow > temps.cSuiv, on dessine une nouvelle image et on augmente temps.cSuiv. Si on veut beaucoup de FPS, on ajoutera un peu de cycles à temps.cSuiv, ou inversement.
* Pour animer un objet, on n'incrémentera pas son déplacement de manière statique à chaque image (pos++). On utilisera le temps qu'il s'est écoulé entre deux frames (pos += temps.cSuiv - temps.cPrec) pour savoir où l'objet sera placé.
* Concernant l'affichage OpenGL, la fonction glutSwapBuffers() permet un affichage en double buffering. Il faut uniquement l'utiliser lorsqu'on est sur le point d'afficher une nouvelle image (temps.cNow > temps.cSuiv). La fonction glutPostRedisplay() permet de redemander l'affichage d'une nouvelle image, il faut toujours utiliser cette fonction à la fin de l'affichage, que la frame précédente soit affichée ou non.