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.

  1. 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.

  2. 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.
  3. 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). 
  4. 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;
  5. 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
       
    }
  6. 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