Débuter avec opengl
Sur cette page
Configuration manuelle d’OpenGL sous Windows
- Exemple de code complet inclus à la fin *
Composants Windows pour OpenGL
WGL
WGL (peut être prononcé wiggle) signifie “Windows-GL”, comme dans “une interface entre Windows et OpenGL” - un ensemble de fonctions de l’API Windows pour communiquer avec OpenGL. Les fonctions WGL ont un préfixe wgl et ses jetons ont un préfixe WGL_.
La version par défaut d’OpenGL prise en charge sur les systèmes Microsoft est 1.1. C’est une version très ancienne (la plus récente est la 4.5). La façon d’obtenir les versions les plus récentes consiste à mettre à jour vos pilotes graphiques, mais votre carte graphique doit prendre en charge ces nouvelles versions.
La liste complète des fonctions WGL peut être trouvée [ici][2].
Interface de périphérique graphique (GDI)
GDI (aujourd’hui mis à jour vers GDI+) est une interface de dessin 2D qui vous permet de dessiner sur une fenêtre dans Windows. Vous avez besoin de GDI pour initialiser OpenGL et lui permettre d’interagir avec lui (mais n’utiliserez pas réellement GDI lui-même).
Dans GDI, chaque fenêtre a un contexte de périphérique (DC) qui est utilisé pour identifier la cible de dessin lors de l’appel de fonctions (vous le passez en paramètre). Cependant, OpenGL utilise son propre contexte de rendu (RC). Ainsi, DC sera utilisé pour créer RC.
Configuration de base
Créer une fenêtre
Donc, pour faire des choses dans OpenGL, nous avons besoin de RC, et pour obtenir RC, nous avons besoin de DC, et pour obtenir DC, nous avons besoin d’une fenêtre. La création d’une fenêtre à l’aide de l’API Windows nécessite plusieurs étapes. Il s’agit d’une routine de base, donc pour une explication plus détaillée, vous devriez consulter une autre documentation, car il ne s’agit pas d’utiliser l’API Windows.
Il s’agit d’une configuration Windows, donc Windows.h
doit être inclus, et le point d’entrée du programme doit être la procédure WinMain
avec ses paramètres. Le programme doit également être lié à opengl32.dll
et à gdi32.dll
(que vous soyez sur un système 64 ou 32 bits).
Nous devons d’abord décrire notre fenêtre en utilisant la structure WNDCLASS
. Il contient des informations sur la fenêtre que nous voulons créer :
/* REGISTER WINDOW */
WNDCLASS window_class;
// Clear all structure fields to zero first
ZeroMemory(&window_class, sizeof(window_class));
// Define fields we need (others will be zero)
window_class.style = CS_OWNDC;
window_class.lpfnWndProc = window_procedure; // To be introduced later
window_class.hInstance = instance_handle;
window_class.lpszClassName = TEXT("OPENGL_WINDOW");
// Give our class to Windows
RegisterClass(&window_class);
/* *************** */
Pour une explication précise de la signification de chaque champ (et pour une liste complète des champs), consultez la documentation MSDN.
Ensuite, nous pouvons créer une fenêtre en utilisant CreateWindowEx
. Une fois la fenêtre créée, nous pouvons acquérir son DC :
/* CREATE WINDOW */
HWND window_handle = CreateWindowEx(WS_EX_OVERLAPPEDWINDOW,
TEXT("OPENGL_WINDOW"),
TEXT("OpenGL window"),
WS_OVERLAPPEDWINDOW,
0, 0,
800, 600,
NULL,
NULL,
instance_handle,
NULL);
HDC dc = GetDC(window_handle);
ShowWindow(window_handle, SW_SHOW);
/* ************* */
Enfin, nous devons créer une boucle de messages qui reçoit les événements de fenêtre du système d’exploitation :
/* EVENT PUMP */
MSG msg;
while (true) {
if (PeekMessage(&msg, window_handle, 0, 0, PM_REMOVE)) {
if (msg.message == WM_QUIT)
break;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
// draw(); <- there goes your drawing
SwapBuffers(dc); // To be mentioned later
}
/* ********** */
Format de pixels
OpenGL a besoin de connaître certaines informations sur notre fenêtre, telles que le nombre de bits de couleur, la méthode de mise en mémoire tampon, etc. Pour cela, nous utilisons un format pixel. Cependant, nous ne pouvons que suggérer au système d’exploitation le type de format de pixel dont nous avons besoin, et le système d’exploitation fournira * le format le plus similaire pris en charge *, nous n’avons pas de contrôle direct sur celui-ci. C’est pourquoi on l’appelle seulement un descripteur.
/* PIXEL FORMAT */
PIXELFORMATDESCRIPTOR descriptor;
// Clear all structure fields to zero first
ZeroMemory(&descriptor, sizeof(descriptor));
// Describe our pixel format
descriptor.nSize = sizeof(descriptor);
descriptor.nVersion = 1;
descriptor.dwFlags = PFD_DRAW_TO_WINDOW | PFD_DRAW_TO_BITMAP | PFD_SUPPORT_OPENGL | PFD_GENERIC_ACCELERATED | PFD_DOUBLEBUFFER | PFD_SWAP_LAYER_BUFFERS;
descriptor.iPixelType = PFD_TYPE_RGBA;
descriptor.cColorBits = 32;
descriptor.cRedBits = 8;
descriptor.cGreenBits = 8;
descriptor.cBlueBits = 8;
descriptor.cAlphaBits = 8;
descriptor.cDepthBits = 32;
descriptor.cStencilBits = 8;
// Ask for a similar supported format and set it
int pixel_format = ChoosePixelFormat(dc, &descriptor);
SetPixelFormat(dc, pixel_format, &descriptor);
/* *********************** */
Nous avons activé la double mise en mémoire tampon dans le champ dwFlags
, nous devons donc appeler SwapBuffers
afin de voir les choses après le dessin.
Contexte de rendu
Après cela, nous pouvons simplement créer notre contexte de rendu :
/* RENDERING CONTEXT */
HGLRC rc = wglCreateContext(dc);
wglMakeCurrent(dc, rc);
/* ***************** */
Notez qu’un seul thread peut utiliser le RC à la fois. Si vous souhaitez l’utiliser à partir d’un autre thread plus tard, vous devez y appeler wglMakeCurrent
pour l’activer à nouveau (cela le désactivera sur le thread où il est actuellement actif, et ainsi de suite).
Obtenir des fonctions OpenGL
Les fonctions OpenGL sont obtenues en utilisant des pointeurs de fonction. La procédure générale est :
- Obtenir d’une manière ou d’une autre des types de pointeurs de fonction (essentiellement les prototypes de fonction)
- Déclarez chaque fonction que nous aimerions utiliser (avec son type de pointeur de fonction)
- Obtenir la fonction réelle
Par exemple, considérez glBegin :
// We need to somehow find something that contains something like this,
// as we can't know all the OpenGL function prototypes
typedef void (APIENTRY *PFNGLBEGINPROC)(GLenum);
// After that, we need to declare the function in order to use it
PFNGLBEGINPROC glBegin;
// And finally, we need to somehow make it an actual function
(“PFN” signifie “pointeur vers une fonction”, puis suit le nom d’une fonction OpenGL et “PROC” à la fin - c’est le nom habituel du type de pointeur de fonction OpenGL.)
Voici comment cela se passe sous Windows. Comme mentionné précédemment, Microsoft ne livre que OpenGL 1.1. Tout d’abord, les types de pointeurs de fonction pour cette version peuvent être trouvés en incluant GL/gl.h
. Après cela, nous déclarons toutes les fonctions que nous avons l’intention d’utiliser comme indiqué ci-dessus (faire cela dans un fichier d’en-tête et les déclarer “extern” nous permettrait de toutes les utiliser après les avoir chargées une fois, simplement en l’incluant). Enfin, le chargement des fonctions OpenGL 1.1 se fait en ouvrant la DLL :
HMODULE gl_module = LoadLibrary(TEXT("opengl32.dll"));
/* Load all the functions here */
glBegin = (PFNGLBEGINPROC)GetProcAddress("glBegin");
// ...
/* *************************** */
FreeLibrary(gl_module);
Cependant, nous voulons probablement un peu plus qu’OpenGL 1.1. Mais Windows ne nous donne pas les prototypes de fonctions ou les fonctions exportées pour quoi que ce soit au-dessus de cela. Les prototypes doivent être acquis auprès du [registre OpenGL][1]. Trois fichiers nous intéressent : GL/glext.h
, GL/glcorearb.h
et GL/wglext.h
.
Afin de compléter GL/gl.h
fourni par Windows, nous avons besoin de GL/glext.h
. Il contient (comme décrit par le registre) “OpenGL 1.2 et au-dessus du profil de compatibilité et des interfaces d’extension” (plus sur les profils et les extensions plus tard, où nous verrons que ce n’est ** en fait pas une bonne idée d’utiliser ces deux fichiers **) .
Les fonctions réelles doivent être obtenues par wglGetProcAddress
(pas besoin d’ouvrir la DLL pour ce type, elles ne sont pas là, utilisez simplement la fonction). Avec lui, nous pouvons récupérer toutes les fonctions d’OpenGL 1.2 et supérieur (mais pas 1.1). Notez que, pour qu’il fonctionne correctement, le contexte de rendu OpenGL doit être créé et mis à jour. Ainsi, par exemple, glClear
:
// Include the header from the OpenGL registry for function pointer types
// Declare the functions, just like before
PFNGLCLEARPROC glClear;
// ...
// Get the function
glClear = (PFNGLCLEARPROC)wglGetProcAddress("glClear");
Nous pouvons en fait créer une procédure wrapper get_proc
qui utilise à la fois wglGetProcAddress
et GetProcAddress
:
// Get function pointer
void* get_proc(const char *proc_name)
{
void *proc = (void*)wglGetProcAddress(proc_name);
if (!proc) proc = (void*)GetProcAddress(gl_module, proc_name); // gl_module must be somewhere in reach
return proc;
}
Donc, pour conclure, nous créerions un fichier d’en-tête rempli de déclarations de pointeur de fonction comme ceci :
extern PFNGLCLEARCOLORPROC glClearColor;
extern PFNGLCLEARDEPTHPROC glClearDepth;
extern PFNGLCLEARPROC glClear;
extern PFNGLCLEARBUFFERIVPROC glClearBufferiv;
extern PFNGLCLEARBUFFERFVPROC glClearBufferfv;
// And so on...
Nous pouvons alors créer une procédure comme load_gl_functions
que nous n’appelons qu’une seule fois, et qui fonctionne ainsi :
glClearColor = (PFNGLCLEARCOLORPROC)get_proc("glClearColor");
glClearDepth = (PFNGLCLEARDEPTHPROC)get_proc("glClearDepth");
glClear = (PFNGLCLEARPROC)get_proc("glClear");
glClearBufferiv = (PFNGLCLEARBUFFERIVPROC)get_proc("glClearBufferiv");
glClearBufferfv = (PFNGLCLEARBUFFERFVPROC)get_proc("glClearBufferfv");
Et vous êtes prêt ! Incluez simplement l’en-tête avec les pointeurs de fonction et GL away.
Meilleure configuration
Profils OpenGL
OpenGL est en développement depuis plus de 20 ans et les développeurs ont toujours été stricts sur la rétrocompatibilité (BC). Ajouter une nouvelle fonctionnalité est très difficile à cause de cela. Ainsi, en 2008, il a été séparé en deux “profils”. Core et compatibilité. Le profil de base brise BC en faveur d’améliorations des performances et de certaines des nouvelles fonctionnalités. Il supprime même complètement certaines fonctionnalités héritées. Le profil de compatibilité maintient BC avec toutes les versions jusqu’à 1.0, et certaines nouvelles fonctionnalités ne sont pas disponibles dessus. Il ne doit être utilisé que pour les anciens systèmes hérités, toutes les nouvelles applications doivent utiliser le profil principal.
- À cause de cela, il y a un problème avec notre configuration de base - elle ne fournit que le contexte qui est rétrocompatible avec OpenGL 1.0. Le format pixel est également limité. Il existe une meilleure approche, en utilisant des extensions.*
Extensions OpenGL
Tout ajout à la fonctionnalité d’origine d’OpenGL est appelé extensions. En règle générale, ils peuvent rendre légales certaines choses qui ne l’étaient pas auparavant, étendre la plage de valeurs des paramètres, étendre GLSL et même ajouter de toutes nouvelles fonctionnalités.
Il existe trois principaux groupes d’extensions : fournisseur, EXT et ARB. Les extensions de fournisseur proviennent d’un fournisseur spécifique, et elles ont une marque spécifique au fournisseur, comme AMD ou NV. Les extensions EXT sont créées par plusieurs fournisseurs travaillant ensemble. Après un certain temps, elles peuvent devenir des extensions ARB, qui sont toutes celles officiellement prises en charge et celles approuvées par ARB.
Pour acquérir les types de pointeurs de fonction et les prototypes de fonction de toutes les extensions et comme mentionné précédemment, tous les types de pointeurs de fonction d’OpenGL 1.2 et supérieur, il faut télécharger les fichiers d’en-tête depuis le [registre OpenGL][1]. Comme indiqué, pour les nouvelles applications, il est préférable d’utiliser le profil de base, il serait donc préférable d’inclure GL/glcorearb.h
au lieu de GL/gl.h
et GL/glext.h
(si vous utilisez GL/glcorearb.h
alors n’incluez pas GL/gl.h
).
Il existe également des extensions pour le WGL, dans GL/wglext.h
. Par exemple, la fonction pour obtenir la liste de toutes les extensions prises en charge est en fait une extension elle-même, le wglGetExtensionsStringARB
(elle renvoie une grande chaîne avec une liste séparée par des espaces de toutes les extensions prises en charge).
L’obtention d’extensions est également gérée via wglGetProcAddress
, nous pouvons donc simplement utiliser notre wrapper comme avant.
Format de pixel avancé et création de contexte
L’extension WGL_ARB_pixel_format
nous permet la création avancée de format de pixel. Contrairement à avant, nous n’utilisons pas de structure. Au lieu de cela, nous passons la liste des attributs recherchés.
int pixel_format_arb;
UINT pixel_formats_found;
int pixel_attributes[] = {
WGL_SUPPORT_OPENGL_ARB, 1,
WGL_DRAW_TO_WINDOW_ARB, 1,
WGL_DRAW_TO_BITMAP_ARB, 1,
WGL_DOUBLE_BUFFER_ARB, 1,
WGL_SWAP_LAYER_BUFFERS_ARB, 1,
WGL_COLOR_BITS_ARB, 32,
WGL_RED_BITS_ARB, 8,
WGL_GREEN_BITS_ARB, 8,
WGL_BLUE_BITS_ARB, 8,
WGL_ALPHA_BITS_ARB, 8,
WGL_DEPTH_BITS_ARB, 32,
WGL_STENCIL_BITS_ARB, 8,
WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB,
WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB,
0
};
BOOL result = wglChoosePixelFormatARB(dc, pixel_attributes, NULL, 1, &pixel_format_arb, &pixel_formats_found);
De même, l’extension WGL_ARB_create_context
nous permet la création de contexte avancée :
GLint context_attributes[] = {
WGL_CONTEXT_MAJOR_VERSION_ARB, 3,
WGL_CONTEXT_MINOR_VERSION_ARB, 3,
WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
0
};
HGLRC new_rc = wglCreateContextAttribsARB(dc, 0, context_attributes);
Pour une explication précise des paramètres et des fonctions, consultez la spécification OpenGL.
Pourquoi n’avons-nous pas commencé par eux ? Eh bien, c’est parce que les extensions nous permettent de faire cela, et pour obtenir des extensions, nous avons besoin de wglGetProcAddress
, mais cela ne fonctionne qu’avec un contexte valide actif. Donc, essentiellement, avant de pouvoir créer le contexte que nous voulons, nous devons déjà avoir un contexte actif, et il est généralement appelé contexte factice.
Cependant, Windows ne permet pas de définir le format de pixel d’une fenêtre plus d’une fois. Pour cette raison, la fenêtre doit être détruite et recréée afin d’appliquer de nouvelles choses :
wglMakeCurrent(dc, NULL);
wglDeleteContext(rc);
ReleaseDC(window_handle, dc);
DestroyWindow(window_handle);
// Recreate the window...
Exemple de code complet :
/* We want the core profile, so we include GL/glcorearb.h. When including that, then
GL/gl.h should not be included.
If using compatibility profile, the GL/gl.h and GL/glext.h need to be included.
GL/wglext.h gives WGL extensions.
Note that Windows.h needs to be included before them. */
#include <cstdio>
#include <Windows.h>
#include <GL/glcorearb.h>
#include <GL/wglext.h>
LRESULT CALLBACK window_procedure(HWND, UINT, WPARAM, LPARAM);
void* get_proc(const char*);
/* gl_module is for opening the DLL, and the quit flag is here to prevent
quitting when recreating the window (see the window_procedure function) */
HMODULE gl_module;
bool quit = false;
/* OpenGL function declarations. In practice, we would put these in a
separate header file and add "extern" in front, so that we can use them
anywhere after loading them only once. */
PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetExtensionsStringARB;
PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB;
PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB;
PFNGLGETSTRINGPROC glGetString;
int WINAPI WinMain(HINSTANCE instance_handle, HINSTANCE prev_instance_handle, PSTR cmd_line, int cmd_show) {
/* REGISTER WINDOW */
WNDCLASS window_class;
// Clear all structure fields to zero first
ZeroMemory(&window_class, sizeof(window_class));
// Define fields we need (others will be zero)
window_class.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
window_class.lpfnWndProc = window_procedure;
window_class.hInstance = instance_handle;
window_class.lpszClassName = TEXT("OPENGL_WINDOW");
// Give our class to Windows
RegisterClass(&window_class);
/* *************** */
/* CREATE WINDOW */
HWND window_handle = CreateWindowEx(WS_EX_OVERLAPPEDWINDOW,
TEXT("OPENGL_WINDOW"),
TEXT("OpenGL window"),
WS_OVERLAPPEDWINDOW,
0, 0,
800, 600,
NULL,
NULL,
instance_handle,
NULL);
HDC dc = GetDC(window_handle);
ShowWindow(window_handle, SW_SHOW);
/* ************* */
/* PIXEL FORMAT */
PIXELFORMATDESCRIPTOR descriptor;
// Clear all structure fields to zero first
ZeroMemory(&descriptor, sizeof(descriptor));
// Describe our pixel format
descriptor.nSize = sizeof(descriptor);
descriptor.nVersion = 1;
descriptor.dwFlags = PFD_DRAW_TO_WINDOW | PFD_DRAW_TO_BITMAP | PFD_SUPPORT_OPENGL | PFD_GENERIC_ACCELERATED | PFD_DOUBLEBUFFER | PFD_SWAP_LAYER_BUFFERS;
descriptor.iPixelType = PFD_TYPE_RGBA;
descriptor.cColorBits = 32;
descriptor.cRedBits = 8;
descriptor.cGreenBits = 8;
descriptor.cBlueBits = 8;
descriptor.cAlphaBits = 8;
descriptor.cDepthBits = 32;
descriptor.cStencilBits = 8;
// Ask for a similar supported format and set it
int pixel_format = ChoosePixelFormat(dc, &descriptor);
SetPixelFormat(dc, pixel_format, &descriptor);
/* *********************** */
/* RENDERING CONTEXT */
HGLRC rc = wglCreateContext(dc);
wglMakeCurrent(dc, rc);
/* ***************** */
/* LOAD FUNCTIONS (should probably be put in a separate procedure) */
gl_module = LoadLibrary(TEXT("opengl32.dll"));
wglGetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC)get_proc("wglGetExtensionsStringARB");
wglChoosePixelFormatARB = (PFNWGLCHOOSEPIXELFORMATARBPROC)get_proc("wglChoosePixelFormatARB");
wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC)get_proc("wglCreateContextAttribsARB");
glGetString = (PFNGLGETSTRINGPROC)get_proc("glGetString");
FreeLibrary(gl_module);
/* ************** */
/* PRINT VERSION */
const GLubyte *version = glGetString(GL_VERSION);
printf("%s\n", version);
fflush(stdout);
/* ******* */
/* NEW PIXEL FORMAT*/
int pixel_format_arb;
UINT pixel_formats_found;
int pixel_attributes[] = {
WGL_SUPPORT_OPENGL_ARB, 1,
WGL_DRAW_TO_WINDOW_ARB, 1,
WGL_DRAW_TO_BITMAP_ARB, 1,
WGL_DOUBLE_BUFFER_ARB, 1,
WGL_SWAP_LAYER_BUFFERS_ARB, 1,
WGL_COLOR_BITS_ARB, 32,
WGL_RED_BITS_ARB, 8,
WGL_GREEN_BITS_ARB, 8,
WGL_BLUE_BITS_ARB, 8,
WGL_ALPHA_BITS_ARB, 8,
WGL_DEPTH_BITS_ARB, 32,
WGL_STENCIL_BITS_ARB, 8,
WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB,
WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB,
0
};
BOOL result = wglChoosePixelFormatARB(dc, pixel_attributes, NULL, 1, &pixel_format_arb, &pixel_formats_found);
if (!result) {
printf("Could not find pixel format\n");
fflush(stdout);
return 0;
}
/* **************** */
/* RECREATE WINDOW */
wglMakeCurrent(dc, NULL);
wglDeleteContext(rc);
ReleaseDC(window_handle, dc);
DestroyWindow(window_handle);
window_handle = CreateWindowEx(WS_EX_OVERLAPPEDWINDOW,
TEXT("OPENGL_WINDOW"),
TEXT("OpenGL window"),
WS_OVERLAPPEDWINDOW,
0, 0,
800, 600,
NULL,
NULL,
instance_handle,
NULL);
dc = GetDC(window_handle);
ShowWindow(window_handle, SW_SHOW);
/* *************** */
/* NEW CONTEXT */
GLint context_attributes[] = {
WGL_CONTEXT_MAJOR_VERSION_ARB, 3,
WGL_CONTEXT_MINOR_VERSION_ARB, 3,
WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
0
};
rc = wglCreateContextAttribsARB(dc, 0, context_attributes);
wglMakeCurrent(dc, rc);
/* *********** */
/* EVENT PUMP */
MSG msg;
while (true) {
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
if (msg.message == WM_QUIT)
break;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
// draw(); <- there goes your drawing
SwapBuffers(dc);
}
/* ********** */
return 0;
}
// Procedure that processes window events
LRESULT CALLBACK window_procedure(HWND window_handle, UINT message, WPARAM param_w, LPARAM param_l)
{
/* When destroying the dummy window, WM_DESTROY message is going to be sent,
but we don't want to quit the application then, and that is controlled by
the quit flag. */
switch(message) {
case WM_DESTROY:
if (!quit) quit = true;
else PostQuitMessage(0);
return 0;
}
return DefWindowProc(window_handle, message, param_w, param_l);
}
/* A procedure for getting OpenGL functions and OpenGL or WGL extensions.
When looking for OpenGL 1.2 and above, or extensions, it uses wglGetProcAddress,
otherwise it falls back to GetProcAddress. */
void* get_proc(const char *proc_name)
{
void *proc = (void*)wglGetProcAddress(proc_name);
if (!proc) proc = (void*)GetProcAddress(gl_module, proc_name);
return proc;
}
Compilé avec g++ GLExample.cpp -lopengl32 -lgdi32
avec MinGW/Cygwin ou cl GLExample.cpp opengl32.lib gdi32.lib user32.lib
avec le compilateur MSVC. Assurez-vous cependant que les en-têtes du registre OpenGL se trouvent dans le chemin d’inclusion. Sinon, utilisez le drapeau -I
pour g++
ou /I
pour cl
afin d’indiquer au compilateur où ils sommes.
[1] : https://www.opengl.org/registry/ [2] : https://msdn.microsoft.com/en-us/library/dd374394(v=vs.85).aspx
Configurez Modern OpenGL 4.1 sur macOS (Xcode, GLFW et GLEW)
1. Installer GLFW
La première étape consiste à créer une fenêtre OpenGL. GLFW est une bibliothèque multiplateforme Open Source pour créer des fenêtres avec OpenGL, pour installer GLFW, téléchargez d’abord ses fichiers depuis [www.glfw.org][1]
[![Page Web GLFW][2]][2]
Extrayez le dossier GLFW et son contenu ressemblera à ceci
[![Contenu du dossier GLFW][3]][3]
Téléchargez et installez CMake pour construire GLFW. Allez sur [www.cmake.org/download/][4], téléchargez CMake et installez-le pour MAC OS X
[![Page Web des téléchargements CMake][5]][5]
Si Xcode n’est pas installé. Téléchargez et installez Xcode depuis le Mac App Store.
[![Xcode du Mac App Store][6]][6]
Créez un nouveau dossier Build dans le dossier GLFW
[![dossier GLFW après avoir créé le dossier “Build”][7]][7]
Ouvrez CMake, cliquez sur le bouton ** Parcourir la source ** pour sélectionner le dossier GLFW (assurez-vous que CMakeLists.txt) se trouve dans ce dossier. Après cela, cliquez sur le bouton Browse Build et sélectionnez le dossier Build nouvellement créé à l’étape précédente.
[![CMake Paths][8]][8]
Cliquez maintenant sur le bouton Configurer et sélectionnez Xcode comme générateur avec l’option Utiliser les compilateurs natifs par défaut, puis cliquez sur Terminé.
[![Makefile pour Xcode][9]][9]
Cochez l’option BUILD_SHARED_LIBS puis cliquez à nouveau sur le bouton Configurer et enfin cliquez sur le bouton Générer.
[![Sélectionnez BUILD_SHARED_LIBS][10]][10]
Après la génération, CMake devrait ressembler à ceci
[![Final CMake][11]][11]
Maintenant, ouvrez Finder et allez dans /usr, créez un nom de dossier local s’il n’y est pas déjà. Ouvrez le dossier local et créez deux dossiers include et lib s’ils ne s’y trouvent pas déjà.
Ouvrez maintenant le dossier GLFW et allez dans Build (où CMake a construit les fichiers). Ouvrez le fichier GLFW.xcodeproj dans Xcode.
[![Fichier de projet Xcode][12]][12]
Sélectionnez installer > Mon Mac puis cliquez sur exécuter (bouton en forme de lecture).
[![Installer GLFW][13]][13]
Il est maintenant installé avec succès (ignorez les avertissements).
Pour vous assurer que Ouvrez le Finder et accédez au dossier /usr/local/lib et que trois fichiers de bibliothèque GLFW y seront déjà présents (sinon, ouvrez le dossier Build dans le dossier GLFW et accédez à **src/Debug ** copier tous les fichiers dans /usr/local/lib)
[![Fichiers de bibliothèque GLFW][14]][14]
Ouvrez le Finder et accédez à /usr/local/include et un dossier GLFW y sera déjà présent avec deux fichiers d’en-tête à l’intérieur par le nom de glfw3.h et glfw3native.h
[![Fichiers d’en-tête GLFW][15]][15]
2. Installer GLEW
GLEW est une bibliothèque multiplateforme qui aide à interroger et à charger les extensions OpenGL. Il fournit des mécanismes d’exécution pour déterminer quelles extensions OpenGL sont prises en charge sur la plate-forme cible. C’est uniquement pour OpenGL moderne (OpenGL version 3.2 et supérieure qui nécessite que les fonctions soient déterminées au moment de l’exécution). Pour installer, téléchargez d’abord ses fichiers depuis [glew.sourceforge.net][16]
[![Page Web GLEW][17]][17]
Extrayez le dossier GLFW et son contenu ressemblera à ceci.
[![Contenu du dossier GLEW][18]][18]
Maintenant, ouvrez Terminal, accédez au dossier GLEW et tapez les commandes suivantes
make
sudo make install
make clean
Maintenant GLEW est installé avec succès. Pour vous assurer qu’il est installé, ouvrez le Finder, allez dans /usr/local/include et un dossier GL y sera déjà présent avec trois fichiers d’en-tête à l’intérieur par le nom de glew.h, glxew .h et wglew.h
[![Fichiers d’en-tête GLEW][19]][19]
Ouvrez le Finder et allez dans /usr/local/lib et les fichiers de la bibliothèque GLEW y seront déjà présents
[![Fichiers de la bibliothèque GLEW][20]][20]
3. Tester et exécuter
Nous avons maintenant installé avec succès GLFW et GLEW. Il est temps de coder. Ouvrez Xcode et créez un nouveau projet Xcode. Sélectionnez Outil de ligne de commande puis continuez et sélectionnez C++ comme langage.
[![Projet Xcode][21]][21]
Xcode créera un nouveau projet de ligne de commande.
Cliquez sur le nom du projet, et sous l’onglet Build Settings, passez de Basic à All, sous la section Search Paths, ajoutez /usr/local/include dans Header Search Paths et ajoutez /usr/local/lib dans les chemins de recherche de la bibliothèque
[![Chemins de recherche][22]][22]
Cliquez sur le nom du projet, et sous l’onglet Build Phases et sous Link With Binary Libraries ajoutez OpenGL.framework et ajoutez également les bibliothèques GLFW et GLEW récemment créées à partir de /usr/local/lib
[![Liens binaires][23]][23]
Nous sommes maintenant prêts à coder dans Modern Open GL 4.1 sur macOS en utilisant C++ et Xcode. Le code suivant créera une fenêtre OpenGL à l’aide de GLFW avec une sortie d’écran vide.
#include <GL/glew.h>
#include <GLFW/glfw3.h>
// Define main function
int main()
{
// Initialize GLFW
glfwInit();
// Define version and compatibility settings
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
glfwWindowHint(GLFW_OPENGL_PROFILE,GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
// Create OpenGL window and context
GLFWwindow* window = glfwCreateWindow(800, 600, "OpenGL", NULL, NULL);
glfwMakeContextCurrent(window);
// Check for window creation failure
if (!window)
{
// Terminate GLFW
glfwTerminate();
return 0;
}
// Initialize GLEW
glewExperimental = GL_TRUE; glewInit();
// Event loop
while(!glfwWindowShouldClose(window))
{
// Clear the screen to black
glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT);
glfwSwapBuffers(window);
glfwPollEvents();
}
// Terminate GLFW
glfwTerminate(); return 0;
}
[![Fenêtre OpenGL vide][24]][24]
[1] : http://www.glfw.org [2] : http://i.stack.imgur.com/YXXOU.png [3] : http://i.stack.imgur.com/6QE70.png [4] : http://www.cmake.org/download/ [5] : http://i.stack.imgur.com/TkDNc.png [6] : http://i.stack.imgur.com/BtoEq.png [7] : http://i.stack.imgur.com/EzceG.png [8] : http://i.stack.imgur.com/N0RTp.png [9] : http://i.stack.imgur.com/8Xnzf.png [10] : http://i.stack.imgur.com/4ffVA.png [11] : http://i.stack.imgur.com/jf3fQ.png [12] : http://i.stack.imgur.com/odeTV.png [13] : http://i.stack.imgur.com/YpZmD.png [14] : http://i.stack.imgur.com/MySGM.png [15] : http://i.stack.imgur.com/M3BSz.png [16] : http://glew.sourceforge.net [17] : http://i.stack.imgur.com/8W8sl.png [18] : http://i.stack.imgur.com/LTq72.png [19] : http://i.stack.imgur.com/2Atrm.png [20] : http://i.stack.imgur.com/4AJdj.png [21] : http://i.stack.imgur.com/hhNhd.png [22] : http://i.stack.imgur.com/T7lMy.png [23] : http://i.stack.imgur.com/xMzCH.png [24] : http://i.stack.imgur.com/AIE8O.png
Création de contexte OpenGL multiplateforme (à l’aide de SDL2)
Création d’une fenêtre avec le contexte OpenGL (chargement de l’extension via GLEW) :
#define GLEW_STATIC
#include <GL/glew.h>
#include <SDL2/SDL.h>
int main(int argc, char* argv[])
{
SDL_Init(SDL_INIT_VIDEO); /* Initialises Video Subsystem in SDL */
/* Setting up OpenGL version and profile details for context creation */
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);
/* A 800x600 window. Pretty! */
SDL_Window* window = SDL_CreateWindow
(
"SDL Context",
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
800, 600,
SDL_WINDOW_OPENGL
);
/* Creating OpenGL Context */
SDL_GLContext gl_context = SDL_GL_CreateContext(window);
/* Loading Extensions */
glewExperimental = GL_TRUE;
glewInit();
/* The following code is for error checking.
* If OpenGL has initialised properly, this should print 1.
* Remove it in production code.
*/
GLuint vertex_buffer;
glGenBuffers(1, &vertex_buffer);
printf("%u\n", vertex_buffer);
/* Error checking ends here */
/* Main Loop */
SDL_Event window_event;
while(1) {
if (SDL_PollEvent(&window_event)) {
if (window_event.type == SDL_QUIT) {
/* If user is exiting the application */
break;
}
}
/* Swap the front and back buffer for flicker-free rendering */
SDL_GL_SwapWindow(window);
}
/* Freeing Memory */
glDeleteBuffers(1, &vertex_buffer);
SDL_GL_DeleteContext(gl_context);
SDL_Quit();
return 0;
}
Création d’OpenGL 4.1 avec C++ et Cocoa
Obtention d’OpenGL
L’une des idées fausses les plus courantes à propos d’OpenGL est qu’il s’agit d’une bibliothèque pouvant être installée à partir de sources tierces. Cette idée fausse conduit à de nombreuses questions sous la forme “comment installer OpenGL” ou “où télécharger le SDK OpenGL”.
Ce n’est pas ainsi qu’OpenGL trouve le chemin dans le système informatique. OpenGL en lui-même n’est qu’un ensemble de spécifications sur les commandes qu’une implémentation doit suivre. C’est donc la mise en œuvre qui compte. Et pour le moment, les implémentations OpenGL font partie des pilotes GPU. Cela * pourrait * changer à l’avenir, lorsque la nouvelle interface de programmation GPU permettra d’implémenter véritablement OpenGL en tant que bibliothèque, mais pour l’instant, il s’agit d’une API de programmation vers les pilotes graphiques.
Lorsque OpenGL a été publié pour la première fois, l’API s’est en quelque sorte retrouvée dans le contrat ABI (Application Binary Interface) de Windows, Solaris et Linux (LSB-4 Desktop) en plus de son origine Sun Irix. Apple a suivi et en fait intégré OpenGL si profondément dans MacOS X, que la version OpenGL disponible est étroitement couplée à la version de MacOS X installée. Cela a pour effet notable que les environnements de programmation système pour ces systèmes d’exploitation (c’est-à-dire la chaîne d’outils du compilateur et de l’éditeur de liens qui cible nativement ces systèmes) doivent fournir également des définitions d’API OpenGL. Il n’est donc pas nécessaire d’installer un SDK pour OpenGL. Il est techniquement possible de programmer OpenGL sur ces systèmes d’exploitation sans avoir à installer un SDK dédié, en supposant qu’un environnement de construction suivant l’ABI ciblée est installé.
Un effet secondaire de ces règles ABI strictes est que la version OpenGL exposée via l’interface de liaison est le plus petit dénominateur commun auquel les programmes exécutés sur la plate-forme cible peuvent s’attendre à être disponible. Par conséquent, les fonctionnalités OpenGL modernes doivent être accessibles via le mécanisme d’extension, qui est décrit en profondeur séparément.
##Linux Sous Linux, il est assez courant de compartimenter les packages de développement pour différents aspects du système, afin que ceux-ci puissent être mis à jour individuellement. Dans la plupart des distributions Linux, les fichiers de développement pour OpenGL sont contenus dans un package dédié, qui est généralement une dépendance d’un méta-package de développement d’applications de bureau. Ainsi, l’installation des fichiers de développement OpenGL pour Linux est généralement prise en charge avec l’installation du ou des méta-paquets de développement de bureau.*
Microsoft Windows
La bibliothèque de liaison API opengl32.dll
(nommée ainsi pour les versions 32 bits et 64 bits de Windows) est livrée par défaut avec toutes les versions de Windows depuis Windows NT-4 et Windows 95B (les deux vers 1997). Cependant, cette DLL ne fournit pas une implémentation OpenGL réelle (à part un logiciel de secours dont le seul but est d’agir comme un filet de sécurité pour les programmes si aucune autre implémentation OpenGL n’est installée). Cette DLL appartient à Windows et ** ne doit pas ** être modifiée ou déplacée ! Les versions modernes d’OpenGL sont livrées dans le cadre du soi-disant Installable Client Driver (ICD) et accessibles via le fichier “opengl32.dll” par défaut qui est préinstallé avec chaque version de Windows. Cependant, il a été décidé en interne par Microsoft que les pilotes graphiques installés via Windows Update n’installeraient/mettraient pas à jour un ICD OpenGL. En tant que telles, les nouvelles installations de Windows avec des pilotes installés automatiquement ne prennent pas en charge les fonctionnalités OpenGL modernes. Pour obtenir un ICD OpenGL avec des fonctionnalités modernes, les pilotes graphiques doivent être téléchargés directement depuis le site Web du fournisseur du GPU et installés manuellement.
En ce qui concerne le développement, aucune mesure supplémentaire ne doit être prise en soi. Tous les compilateurs C/C++ suivant les spécifications Windows ABI sont livrés avec des en-têtes et le stub de l’éditeur de liens (opengl32.lib) requis pour créer et lier des exécutables qui utilisent OpenGL.
Créer un contexte Opengl avec Java et LWJGL 3.0
Dans cet exemple de code, nous allons créer une fenêtre Opengl vierge à l’aide de LWJGL 3.0+, cela ne contient pas d’étapes pour créer le projet dans votre IDE
[![entrez la description de l’image ici][1]][1]
- Créez un nom de classe WindowManager qui contiendra toutes les chaudières plate code for creating a opengl context window on screen
WindowManager.java
import org.lwjgl.glfw.*;
import static org.lwjgl.glfw.Callbacks.*;
import static org.lwjgl.glfw.GLFW.*;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.system.MemoryUtil.*;
/**
* Class Containing code related to inflating Opengl Window
*/
public class Displaymanager {
private static long window;
public static void createDisplay(){
// Setup an error callback. The default implementation
// will print the error message in System.err.
GLFWErrorCallback.createPrint(System.err).set();
// Initialize GLFW. Most GLFW functions will not work before doing this.
if ( !glfwInit() )
throw new IllegalStateException("Unable to initialize GLFW");
// Configure our window
glfwDefaultWindowHints(); // optional, the current window hints are already the default
glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE); // the window will stay hidden after creation
glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); // the window will be resizable
int WIDTH = 300;
int HEIGHT = 300;
// Create the window
window = glfwCreateWindow(WIDTH, HEIGHT, "Hello World!", NULL, NULL);
if ( window == NULL )
throw new RuntimeException("Failed to create the GLFW window");
// Setup a key callback. It will be called every time a key is pressed, repeated or released.
glfwSetKeyCallback(window, (window, key, scancode, action, mods) -> {
if ( key == GLFW_KEY_ESCAPE && action == GLFW_RELEASE )
glfwSetWindowShouldClose(window, true); // We will detect this in our rendering loop
});
// Get the resolution of the primary monitor
GLFWVidMode vidmode = glfwGetVideoMode(glfwGetPrimaryMonitor());
// Center our window
glfwSetWindowPos(
window,
(vidmode.width() - WIDTH) / 2,
(vidmode.height() - HEIGHT) / 2
);
// Make the OpenGL context current
glfwMakeContextCurrent(window);
// Enable v-sync
glfwSwapInterval(1);
// Make the window visible
glfwShowWindow(window);
}
public static boolean isCloseRequested(){
return glfwWindowShouldClose(window);
}
public static void updateDisplay(){
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // clear the framebuffer
glfwSwapBuffers(window); // swap the color buffers
// Poll for window events. The key callback above will only be
// invoked during this call.
glfwPollEvents();
}
public static void destroyDisplay(){
// Terminate GLFW and free the error callback
cleanUp();
glfwTerminate();
glfwSetErrorCallback(null).free();
}
private static void cleanUp() {
// Free the window callbacks and destroy the window
glfwFreeCallbacks(window);
glfwDestroyWindow(window);
}
}
- Créez ensuite une classe contenant la boucle de rendu principale, qui appellera toutes les fonctions ci-dessus créées
OpenGlMain.java
import org.lwjgl.opengl.GL;
import renderEngine.Displaymanager;
import static org.lwjgl.opengl.GL11.glClearColor;
/**
* Class to test the opengl Window
*/
public class OpenGlMain {
public static void main(String[] args) {
Displaymanager.createDisplay();
// This line is critical for LWJGL's interoperation with GLFW's
// OpenGL context, or any context that is managed externally.
// LWJGL detects the context that is current in the current thread,
// creates the GLCapabilities instance and makes the OpenGL
// bindings available for use.
GL.createCapabilities();
while (!Displaymanager.isCloseRequested()){
// Set the clear color
glClearColor(1.0f, 0.0f, 0.0f, 0.0f);
Displaymanager.updateDisplay();
}
Displaymanager.destroyDisplay();
}
}
Pour plus de détails, consultez le [Guide LWJGL][2]
[1] : http://i.stack.imgur.com/cWrS3.png [2] : https://www.lwjgl.org/guide