Pour créer une fenêtre OpenGL, il y a deux possibilités :
- utiliser GLUT qui permet de s'affranchir de détails techniques propres à Windows (ou linux...). Le but du post ici n'est pas de faire un tutorial sur GLUT, utilisez celui là qui est très bien fait !
- utiliser les fonctions de Windows.
C'est cette deuxième version que nous allons détailler.
Tout d'abord, relisez bien mes
cours sur Windows pour que l'on parte sur les mêmes bases...
Je suppose donc que vous avez compris l'intérêt de la fonction MainProc...
Pour commencer, créons une fenêtre OpenGL... On ne va pas faire comme dans mon cours car on veux pouvoir la paramétrer plus en détails...
Voila le code pour créer une fenêtre OpenGL :
- Code: Tout sélectionner
BOOL fenetre::CreeGLWindow(char* title, int width, int height, int bits, bool fullscreenflag)
{
GLuint PixelFormat;
WNDCLASS wc;
DWORD dwExStyle;
DWORD dwStyle;
RECT WindowRect;
WindowRect.left=(long)0;
WindowRect.right=(long)width;
WindowRect.top=(long)0;
WindowRect.bottom=(long)height;
// Met a jour l'info de fullscreen
fullscreen=fullscreenflag;
// Recupere l'instance de la fenetre
hInstance = GetModuleHandle(NULL);
// Redessine si modification de la taille ou de la position et garde un seul DC pour la fenetre.
wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
// fonction de traitement des messages (voir mon cours)
wc.lpfnWndProc = (WNDPROC) fenetre::MainProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
// Icone par default
wc.hIcon = LoadIcon(NULL, IDI_WINLOGO);
// Curseur par default
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
// Pas de fond pour Opengl (c'est justement lui qui dessinera le fond)
wc.hbrBackground = NULL;
// On ne veut pas de menu
wc.lpszMenuName = NULL;
// Nom de la fenetre
wc.lpszClassName = "OpenGL";
// Essaye de creer la class fenetre :
if (!RegisterClass(&wc))
{
MessageBox(fenetre::hWnd,"Impossible de cree la class fenetre....","ERREUR",MB_OK|MB_ICONEXCLAMATION);
return FALSE;
}
if (fullscreen)// Est on en plein ecran?
{
//oui, alors on passe la fenêtre en fullscreen...
DEVMODE dmScreenSettings;
EnumDisplaySettings(NULL,ENUM_CURRENT_SETTINGS,&dmScreenSettings);
dmScreenSettings.dmSize=sizeof(dmScreenSettings);
dmScreenSettings.dmPelsWidth = width;
dmScreenSettings.dmPelsHeight = height;
dmScreenSettings.dmBitsPerPel = bits;
dmScreenSettings.dmFields=DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT;
dmScreenSettings.dmDisplayFrequency=70;
// Essaye de faire les changements de rezo. NOTE: CDS_FULLSCREEN permet d'enlever la bar demarrer
if (ChangeDisplaySettings(&dmScreenSettings,CDS_FULLSCREEN)!=DISP_CHANGE_SUCCESSFUL)
{
// Si ce n'est pas reussi, on donne le choix d'essayer en fenetre
if (MessageBox(fenetre::hWnd,"Le mode plein ecran n'est pas suporté...\n essayer en mode fenetré?","Initialisation",MB_YESNO|MB_ICONEXCLAMATION)==IDYES)
{
fullscreen=FALSE; // Fenetre choisi. Fullscreen = FALSE
}
else
{
// Erreur, le programme ferme :
MessageBox(fenetre::hWnd,"Erreur d'initialisation...","ERREUR",MB_OK|MB_ICONSTOP);
return FALSE;
}
}
}
if (fullscreen)// Si on est en plein ecran
{
//alors on a un style de fenêtre particulier
dwExStyle=WS_EX_APPWINDOW;
dwStyle=WS_POPUP;
ShowCursor(FALSE);
}
else
{
//sinon, on a un style de fenêtre normal :
dwExStyle=WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
dwStyle=WS_OVERLAPPEDWINDOW;
}
//on récupère les dimensions de la fenetre :
AdjustWindowRectEx(&WindowRect, dwStyle, FALSE, dwExStyle);
// Cree la fenetre
if (!(hWnd=CreateWindowEx(dwExStyle,
"OpenGL",// Nom de la class
title,// Nom de la fenetre
dwStyle |// Style de la fenetre
WS_CLIPSIBLINGS |
WS_CLIPCHILDREN,
0, 0,// Position de la fenetre
WindowRect.right-WindowRect.left,// Calcule la largeur
WindowRect.bottom-WindowRect.top,// Calcule la hauteur
NULL,
NULL,
hInstance,// Instance
NULL)))
{
//problème, donc on :
FinGL();// supprime le contexte
MessageBox(fenetre::hWnd,"Creation de la fenetre echoué.","ERREUR",MB_OK|MB_ICONEXCLAMATION);
return FALSE;
}
static PIXELFORMATDESCRIPTOR pfd=
{
sizeof(PIXELFORMATDESCRIPTOR),// Taille du descripteur de fenetre
1,// Numero de version
PFD_DRAW_TO_WINDOW |// Le format sera pour une fenetre
PFD_SUPPORT_OPENGL |// Le format sera pour Opengl
PFD_DOUBLEBUFFER,// Le format sera en double buffering
PFD_TYPE_RGBA,// Le format sera en RGBA
bits,// Profondeur de couleur (32 ici)
0, 0, 0, 0, 0, 0,
0,
0,
0,
0, 0, 0, 0,
16, // Z-Buffer
0,// Pas de Stencil Buffer
0,// Pas de buffer auxilliere
PFD_MAIN_PLANE,
0,
0, 0, 0
};
if (!(hDC=GetDC(hWnd)))// A t on un DC
{
//erreur, donc on quitte :
FinGL();// supprime le contexte
MessageBox(fenetre::hWnd,"Ne peut pas creer de support OpenGL ...","ERREUR",MB_OK|MB_ICONEXCLAMATION);
return FALSE;
}
if (!(PixelFormat=ChoosePixelFormat(hDC,&pfd)))
{
//si on ne trouve pas de format de pixel utilisable
FinGL();// supprime le contexte
MessageBox(fenetre::hWnd,"Ne trouve pas de format de pixel utilisable ...","ERREUR",MB_OK|MB_ICONEXCLAMATION);
return FALSE;
}
if(!SetPixelFormat(hDC,PixelFormat,&pfd))
{
FinGL();// supprime le contexte
MessageBox(fenetre::hWnd,"Ne peut pas utiliser le format de pixel ...","ERREUR",MB_OK|MB_ICONEXCLAMATION);
return FALSE;
}
if (!(hRC=wglCreateContext(hDC)))
{
FinGL();// supprime le contexte
MessageBox(fenetre::hWnd,"Ne peut pas cree de context d'affichage ...","ERREUR",MB_OK|MB_ICONEXCLAMATION);
return FALSE;
}
if(!wglMakeCurrent(hDC,hRC))
{
FinGL();// supprime le contexte
MessageBox(fenetre::hWnd,"Ne peut pas activer le context d'affichage ...","ERREUR",MB_OK|MB_ICONEXCLAMATION);
return FALSE;
}
ShowWindow(hWnd,SW_SHOW);// affiche la fenetre
SetForegroundWindow(hWnd);// Met en priorité superieure
SetFocus(hWnd); // Redirige le clavier vers la fenetre
return TRUE;// Success
}
Une fois la fenetre faite, il faut traiter les messages qui lui arrivent... C'est ici que nous avons besoin de MainProc ! Un petit exemple de MainProc qui enregistre toutes les touches pressées dans un tableau ainsi que les mouvements de la souris :
- Code: Tout sélectionner
LRESULT CALLBACK fenetre::WndProc( HWND hWnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam)
{
switch (uMsg)// Dispatche les messages de windows
{
case WM_KEYDOWN:// Une touche est pressée?
{
keys[wParam] = true;// Si oui, on la marque à vrai
return 0;
}
case WM_KEYUP:// Une touche est relachée?
{
keys[wParam] = false;// Si oui, on la marque à faux
return 0;
}
case WM_ACTIVATE:// Une activation de la fenetre?
{
if (!HIWORD(wParam))// Regarde si c'est une activation
{
active=true;
}
else
{
active=false;// Ou une desactivation
}
return 0;
}
case WM_COMMAND:// Intercepte les messages que j'ai defini
{
};
case WM_SYSCOMMAND:// Intercepte les messages systemes
{
switch (wParam)
{
case SC_SCREENSAVE:// Economiseur d'ecran se declanche?
case SC_MONITORPOWER:// Economie d'energie se declanche?
return true;// Empeche d'arriver
}
break;
}
case WM_CLOSE:// Doit on fermet la fenetre?
{
PostQuitMessage(0);// Quitte l'appli
return 0;
}
case WM_SIZE:// Redimension de la fenetre?
{
Redimension(LOWORD(lParam),HIWORD(lParam));
return 0;
}
case WM_LBUTTONDOWN://souris droite enfoncé
{
keys[259] = true;// Si oui, on la marque à vrai
return 0;
}
break;
case WM_LBUTTONUP://souris droite relachée
{
keys[259] = false;// Si oui, on la marque à vrai
return 0;
}
case WM_MBUTTONDOWN://souris milieu enfoncé
{
keys[258] = true;// Si oui, on la marque à vrai
return 0;
}
break;
case WM_MBUTTONUP://souris milieu relachée
{
keys[258] = false;// Si oui, on la marque à vrai
return 0;
}
break;
case WM_RBUTTONDOWN://souris droite enfoncé
{
keys[257] = true;// Si oui, on la marque à vrai
return 0;
}
break;
case WM_RBUTTONUP://souris droite relachée
{
keys[257] = false;// Si oui, on la marque à faux
return 0;
}
break;
case WM_MOUSEMOVE:
{
sourisx = LOWORD (lParam);
sourisy = HIWORD (lParam);
sourisdx=ancSourisx-sourisx;
sourisdy=ancSourisy-sourisy;
ancSourisx = sourisx;
ancSourisy = sourisy;
return 0;
}
break;
}
// Passe les autres messages à DefWindowProc
return DefWindowProc(hWnd,uMsg,wParam,lParam);
}
Bon, avec ce début, vous ne pouvez pas encore faire grand chose (juste prendre un tube d'aspirine), inspirez vous pour la suite du TP de N4th (
TP sur les pointeurs), ou du site suivant :
http://neogamedev.chable.net/?PageID=2000