ATTENTION : ceci est la documentation d'une version antérieure de SFML ; la documentation de la dernière version officielle est accessible via le menu principal
Tutoriel - Module de fenêtrage - Utiliser OpenGL
Introduction
Ce tutoriel ne traite pas d'OpenGL en lui-même, mais seulement de la manière d'utiliser le module de fenêtrage pour s'interfacer avec OpenGL. Comme vous le savez sans doute, l'une des fonctionnalités les plus importantes d'OpenGL est la portabilité. Cependant, pour fonctionner OpenGL requiert que vous ayiez créé un contexte de rendu en premier lieu. Et les contextes de rendu sont tout sauf portables ; chaque système d'exploitation possède son propre moyen de les créer. C'est pourquoi les gens utilisent habituellement une bibliothèque portable afin d'obtenir un système de fenêtrage et d'évènements portable capable de faire tourner OpenGL quelque soit le système. Les bibliothèques les plus connues pour le faire sont SDL et GLUT, mais elles sont écrites en C et pas toujours pratiques à utiliser en C++, particulièrement si vous avez une approche orientée objet. Elles souffrent également de certains manques essentiels, comme être utilisables dans plusieurs fenêtres simultanées ou dans des interfaces existantes.
Initialisation
Pour utiliser OpenGL, vous devez tout d'abord ajouter quelques en-têtes :
#include <SFML/Window.hpp> #include <GL/gl.h> #include <GL/glu.h>
Ici nous allons également utiliser GLU (OpenGL Utility Toolkit). L'ordre des inclusions est important : si vous incluez les en-têtes OpenGL avant celui de la SFML, vous allez avoir de nombreuses erreurs de compilation. Cela s'explique par le fait qu'il faut toujours inclure les en-têtes du système d'exploitation (ce qui est fait par la SFML) avant les en-têtes OpenGL, afin que certains types spécifiques soient bien définis.
Aucune étape supplémentaire n'est requise pour initialiser SFML lorsque vous voulez utiliser OpenGL. Nous pouvons donc créer une fenêtre comme nous l'avons vu auparavant :
sf::Window App(sf::VideoMode(800, 600, 32), "SFML OpenGL");
Ainsi qu'une horloge pour mesurer le temps écoulé :
sf::Clock Clock;
Une fois qu'une fenêtre est créée, nous avons un contexte de rendu valide. C'est donc le bon moment pour effectuer toutes nos initialisations spécifiques à OpenGL. Ici nous mettons en place une vue en perspective et nous activons le tampon de profondeur (Z-Buffer) :
// Initialisation des valeurs d'effacement pour les tampons de couleur et de profondeur glClearDepth(1.f); glClearColor(0.f, 0.f, 0.f, 0.f); // Activation de la lecture et de l'écriture dans le tampon de profondeur glEnable(GL_DEPTH_TEST); glDepthMask(GL_TRUE); // Mise en place d'une projection perspective glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(90.f, 1.f, 1.f, 500.f);
Si vous voulez utiliser le Z-buffer ou le stencil buffer, vous pouvez récupérer leur taille auprès de la fenêtre :
unsigned int DepthBits = App.GetDepthBits(); // 8 / 16 / 32 unsigned int StencilBits = App.GetStencilBits(); // 8 / 16 / 32
La SFML choisira toujours la meilleure configuration pour les tampons de couleur / profondeur / stencil ; ainsi vous n'aurez pas de stencil buffer que si votre carte graphique ne le supporte pas.
Les appels OpenGL peuvent être effectués avant même qu'une fenêtre soit créée : la SFML gère son propre contexte OpenGL indépendamment de toute fenêtre. Tous les contextes sont partagés, c'est-à-dire que vous pouvez créer une texture pendant que FenetreA est active, et l'utiliser pour dessiner sur FenetreB.
Boucle principale - affichage d'un cube
La boucle principale démarre comme précédemment, avec la gestion des évènements :
bool Running = true; while (Running) { sf::Event Event; while (App.GetEvent(Event)) { // Du code pour stopper l'application à la fermeture ou lorsque la touche echap est enfoncée }
Mais ici nous avons à gérer un évènements supplémentaire : Resized.
Nous devons le gérer car lorsque la taille de la fenêtre change, il faut ajuster le viewport OpenGL
afin qu'il corresponde à la nouvelle taille. Le viewport est la zone de la fenêtre dans laquelle
la scène va être affichée, donc si vous ne l'ajustez pas lorsque la fenêtre est redimensionnée,
votre scène sera dessinée dans un petit sous-rectangle de la fenêtre.
if (Event.Type == sf::Event::Resized)
glViewport(0, 0, Event.Size.Width, Event.Size.Height);
Vous pouvez maintenant commencer à afficher une nouvelle frame. Avant d'appeler une fonction OpenGL,
vous devez vous assurer que c'est la bonne fenêtre qui est active. Ici nous ne nous en occupons pas
car nous n'avons qu'une fenêtre, mais si vous devez en gérer plusieurs il faudra en tenir compte.
Pour rendre une fenêtre active, vous pouvez appeler sa fonction SetCurrent :
App.SetCurrent();
Puis, la première chose à faire est d'effacer les tampons de couleur et de profondeur afin d'effacer le contenu de la frame précédente :
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Nous sommes maintenant prêt à afficher un cube. Tout d'abord, nous définissons sa position et son orientation. Nous allons faire évoluer l'orientation avec le temps écoulé, pour ajouter un peu de mouvement.
glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glTranslatef(0.f, 0.f, -200.f); glRotatef(Clock.GetElapsedTime() * 50, 1.f, 0.f, 0.f); glRotatef(Clock.GetElapsedTime() * 30, 0.f, 1.f, 0.f); glRotatef(Clock.GetElapsedTime() * 90, 0.f, 0.f, 1.f);
Puis nous dessinons le cube :
glBegin(GL_QUADS);
glVertex3f(-50.f, -50.f, -50.f);
glVertex3f(-50.f, 50.f, -50.f);
glVertex3f( 50.f, 50.f, -50.f);
glVertex3f( 50.f, -50.f, -50.f);
glVertex3f(-50.f, -50.f, 50.f);
glVertex3f(-50.f, 50.f, 50.f);
glVertex3f( 50.f, 50.f, 50.f);
glVertex3f( 50.f, -50.f, 50.f);
glVertex3f(-50.f, -50.f, -50.f);
glVertex3f(-50.f, 50.f, -50.f);
glVertex3f(-50.f, 50.f, 50.f);
glVertex3f(-50.f, -50.f, 50.f);
glVertex3f(50.f, -50.f, -50.f);
glVertex3f(50.f, 50.f, -50.f);
glVertex3f(50.f, 50.f, 50.f);
glVertex3f(50.f, -50.f, 50.f);
glVertex3f(-50.f, -50.f, 50.f);
glVertex3f(-50.f, -50.f, -50.f);
glVertex3f( 50.f, -50.f, -50.f);
glVertex3f( 50.f, -50.f, 50.f);
glVertex3f(-50.f, 50.f, 50.f);
glVertex3f(-50.f, 50.f, -50.f);
glVertex3f( 50.f, 50.f, -50.f);
glVertex3f( 50.f, 50.f, 50.f);
glEnd();
Enfin, nous pouvons terminer notre boucle principale en affichant le rendu à l'écran :
App.Display();
Et voilà, vous devriez avoir un cube blanc tournant sur un fond noir. Comme d'habitude, aucune destruction explicite n'est nécessaire après la fin de la boucle principale, tout est nettoyé correctement.
Vérifier les extensions et possibilités OpenGL
SFML fournit également une interface facile d'utilisation pour récupérer les extensions et possibilités
supportées par OpenGL, via la classe
sf::OpenGLCaps.
Vous pouvez vérifier qu'une extension est supportée avec la fonction CheckExtension, et récupérer
diverses possibilités avec les autres fonctions :
// On vérifie qu'on peut créer des textures avec des dimensions non puissances de deux bool NonPowerOfTwoTextures = sf::OpenGLCaps::CheckExtension("GL_ARB_texture_non_power_of_two"); // On récupère la taille de texture maximale int MaxTextureSize = sf::OpenGLCaps::GetMaxTextureSize();
sf::OpenGLCaps utilise en interne
GLEW
pour gérer les extensions, vous pouvez donc utiliser les fonctions associées aux extensions (comme par exemple
glCreateProgramObjectARB) sans avoir à procéder à aucun chargement explicite.
Conclusion
Utiliser OpenGL avec la SFML est très facile, et ne nécessite aucune étape supplémentaire comparé à une utilisation classique de la SFML. Vous pouvez avoir un système de fenêtrage OpenGL robuste, portable et orienté objet avec seulement quelques lignes de code.
Vous savez maintenant à peu près tout sur le module de fenêtrage de la SFML. Vous avez appris à installer l'API SFML, ouvrir une fenêtre, gérer correctement les entrées, les évènements et le temps, et à interfacer OpenGL. Vous pouvez maintenant sauter à une autre section pour apprendre à utiliser un nouveau module.
Téléchargez le code source- window-opengl.cpp (3.47 Ko)
