Initialisation
Cette partie porte surtout sur MFC, car ici il ne s'affiche rien a
l'ecran : il y a juste une fenetre et l'initialisation d'OpenGL. Si vous creez la fenetre
avec Glut, cette partie ne vous concerne pas vraiment.
Cette partie est quasiment la traduction http://devcentral.iftech.com/learning/Tutorials/mfc-win32/opengl/2.asp.htm,
il n'y a de toute facon qu'une maniere d'initialiser une fenetre. Il n'est indispensable
de tout comprendre, et il est rare d'ecrie deux fois cette partie. Le mieux est d'avoir un
projet de base reutilisable. D'ailleurs le code contenu dans cette page vient en partie de
DevCentral.
- Premiere chose a faire : creer un "Workspace" avec "File",
"New", "MFC AppWizard (exe)". Choisir le repertoire ou mettre le
projet puis lui donner un nom (un repertoire du nom du projet est cree).
Appuyer sur OK, choisir "Single Document", accepter la suite sauf la
"Toolbar" et "Printing", la "Status Bar" est au choix (cela
peut etre utile). Faire Terminer. L'AppWizard a cree differentes classes qui facilitent la
creation de l'application : seul probleme il fait tout sans rien expliquer, mais pour plus
de renseignements il y a des bouquins.
- Ensuite il faut ajouter les librairies OpenGL : dans "Project",
"Settings", changer "Settings for" a "All Configurations" et
aller dans l'onglet "Link". Dans la ligne "Object/library modules :"
mettre "opengl32.lib glu32.lib".
Dans stdafx.h, rajouter :
...
#include <afxwin.h> // MFC core and standard components
#include <afxext.h> // MFC extensions
#include <gl/gl.h>
#include <gl/glu.h>
#ifndef _AFX_NO_AFXCMN_SUPPORT
#include <afxcmn.h>
// MFC support for
Windows Common Controls
#endif // _AFX_NO_AFXCMN_SUPPORT
...
L'interet est que tout les fichiers ont des #include "stdafx.h", donc plus
besoin d'en mettre d'autres pour l'OpenGL.
Compiler le tout pour verifier si tout est la.
- Rajouter a la classe View la fonction PreCreateWindow avec ClassWizard (Ctrl + W), la
modifier pour qu'elle ressemble a ca :
BOOL CTutorial1View::PreCreateWindow(CREATESTRUCT& cs)
{
// TODO: Modify the Window class or styles here by modifying
// the CREATESTRUCT cs
cs.style |= (WS_CLIPCHILDREN | WS_CLIPSIBLINGS);
cs.lpszClass = AfxRegisterWndClass(CS_OWNDC);
return CView::PreCreateWindow(cs);
}
Il s'agit juste de changer les proprietes de la fenetre pour qu'OpenGL fonctionne.
L'attribut CS_OWNDC est conseille avec certaines cartes graphiques dont les TNT, Rage Pro
et quelques autres cartes recentes (je ne sais pas exactement pourquoi).
- Rajouter une fonction membre a la classe View, appelee SetWindowPixelFormat :
BOOL CTutorial1View::SetWindowPixelFormat(HDC hDC)
{
PIXELFORMATDESCRIPTOR pixelDesc;
pixelDesc.nSize =
sizeof(PIXELFORMATDESCRIPTOR);
pixelDesc.nVersion = 1;
pixelDesc.dwFlags = PFD_DRAW_TO_WINDOW |
PFD_SUPPORT_OPENGL |
PFD_DOUBLEBUFFER |
PFD_STEREO_DONTCARE;
pixelDesc.iPixelType = PFD_TYPE_RGBA;
pixelDesc.cColorBits = 32;
pixelDesc.cRedBits = 8;
pixelDesc.cRedShift = 16;
pixelDesc.cGreenBits = 8;
pixelDesc.cGreenShift = 8;
pixelDesc.cBlueBits = 8;
pixelDesc.cBlueShift = 0;
pixelDesc.cAlphaBits = 0;
pixelDesc.cAlphaShift = 0;
pixelDesc.cAccumBits = 64;
pixelDesc.cAccumRedBits = 16;
pixelDesc.cAccumGreenBits= 16;
pixelDesc.cAccumBlueBits = 16;
pixelDesc.cAccumAlphaBits= 0;
pixelDesc.cDepthBits = 32;
pixelDesc.cStencilBits = 8;
pixelDesc.cAuxBuffers = 0;
pixelDesc.iLayerType = PFD_MAIN_PLANE;
pixelDesc.bReserved = 0;
pixelDesc.dwLayerMask = 0;
pixelDesc.dwVisibleMask = 0;
pixelDesc.dwDamageMask = 0;
m_GLPixelIndex = ChoosePixelFormat(hDC, &pixelDesc);
if (m_GLPixelIndex==0)
{
m_GLPixelIndex = 1; // Let's
choose a default index.
if (DescribePixelFormat( hDC, m_GLPixelIndex,
sizeof(PIXELFORMATDESCRIPTOR), &pixelDesc) == 0)
{
DWORD errorCode =
GetLastError();
CString errorStr;
errorStr.Format("DescribePixelFormat returned error code %d.", errorCode);
AfxMessageBox(errorStr);
return FALSE;
}
}
if (SetPixelFormat(hDC, m_GLPixelIndex, &pixelDesc) ==FALSE)
{
DWORD errorCode = GetLastError();
CString errorStr;
errorStr.Format("SetPixelFormat returned
error code %d.", errorCode);
AfxMessageBox(errorStr);
return FALSE;
}
return TRUE;
}
Il faut aussi rajouter une variable a la classe :
int m_GLPixelIndex;
Par convention, les variables membres d'une classe commencent par m_.
Pour plus de details sur ce que fait cette fonction, voir l'aide sur ChoosePixelFormat et
SetPixelFormat.
Ajouter ensuite une fonction CreateViewGLContext(HDC hDC) :
BOOL CTutorial1View::CreateViewGLContext(HDC hDC)
{
m_hGLContext = wglCreateContext(hDC);
if (m_hGLContext == NULL)
{
DWORD errorCode = GetLastError();
CString errorStr;
errorStr.Format("wglCreateContext returned
error code %d.", errorCode);
AfxMessageBox(errorStr);
return FALSE;
}
if (wglMakeCurrent(hDC, m_hGLContext)==FALSE)
{
DWORD errorCode = GetLastError();
CString errorStr;
errorStr.Format("wglCreateContext returned
error code %d.", errorCode);
AfxMessageBox(errorStr);
return FALSE;
}
return TRUE;
}
Il reste encore a appeler cette fonction. Avec ClassWizard, ajouter la fonction OnCreate
et la modifier ainsi :
int CTutorial1View::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CView::OnCreate(lpCreateStruct) == -1)
return -1;
// TODO: Add your specialized creation code here
HWND hWnd = GetSafeHwnd();
HDC hDC = ::GetDC(hWnd);
if (SetWindowPixelFormat(hDC)==FALSE)
return 0;
if (CreateViewGLContext(hDC)==FALSE)
return 0;
return 0;
}
Ajouter la variable :
HGLRC m_hGLContext;
- Il faut quitter aussi quitter proprement, chose a faire dans OnDestroy (ClassWizard) :
void CTutorial1View::OnDestroy()
{
if(wglGetCurrentContext()!=NULL)
{
// make the rendering context not current
wglMakeCurrent(NULL, NULL) ;
}
if (m_hGLContext!=NULL)
{
wglDeleteContext(m_hGLContext);
m_hGLContext = NULL;
}
// Now the associated DC can be released.
CView::OnDestroy();
// TODO: Add your message handler code here
}
- Derniere chose : initialiser les variables membres
CTutorial1View::CTutorial1View()
{
// TODO: add construction code here
m_hGLContext = NULL;
m_GLPixelIndex = 0;
}
Code source : Tutorial1.zip
Etape Suivante