I. Création de la fenêtre Windows

Image non disponible

Pour commencer, nous créons une fenêtre Windows en utilisant l'API Windows. Je n'expliquerai pas ce code puisqu'il est spécifique à Windows. Regardez la documentation MSDN ou un livre sur Windows pour plus de détails.

 
Sélectionnez
#include <irrlicht.h>
#ifndef _IRR_WINDOWS_
#error Windows only example
#else
#include <windows.h> // Cet exemple s'exécute uniquement sous Windows.
#include <iostream>
#include "driverChoice.h"

using namespace irr;

#pragma comment(lib, "irrlicht.lib")

HWND hOKButton;
HWND hWnd;

static LRESULT CALLBACK CustomWndProc(HWND hWnd, UINT message,
        WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_COMMAND:
        {
            HWND hwndCtl = (HWND)lParam;
            int code = HIWORD(wParam);

            if (hwndCtl == hOKButton)
            {
                DestroyWindow(hWnd);
                PostQuitMessage(0);
                return 0;
            }
        }
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;

    }

    return DefWindowProc(hWnd, message, wParam, lParam);
}

Maintenant, demandons un pilote et créons une fenêtre spécifique à Windows.

 
Sélectionnez
int main()
{
    // Demande à l'utilisateur un pilote.
    video::E_DRIVER_TYPE driverType=driverChoiceConsole();
    if (driverType==video::EDT_COUNT)
        return 1;

    printf("Select the render window (some dead window may exist too):\n"\
        " (a) Window with button (via CreationParam)\n"\
        " (b) Window with button (via beginScene)\n"\
        " (c) Own Irrlicht window (default behavior)\n"\
        " (otherKey) exit\n\n");

    char key;
    std::cin >> key;
    if (key != 'a' && key != 'b' && key != 'c')
        return 1;

    HINSTANCE hInstance = 0;
    // Crée une boîte de dialogue.

    const char* Win32ClassName = "CIrrlichtWindowsTestDialog";

    WNDCLASSEX wcex;
    wcex.cbSize         = sizeof(WNDCLASSEX);
    wcex.style          = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc    = (WNDPROC)CustomWndProc;
    wcex.cbClsExtra     = 0;
    wcex.cbWndExtra     = DLGWINDOWEXTRA;
    wcex.hInstance      = hInstance;
    wcex.hIcon          = NULL;
    wcex.hCursor        = LoadCursor(NULL, IDC_ARROW);
    wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW);
    wcex.lpszMenuName   = 0;
    wcex.lpszClassName  = Win32ClassName;
    wcex.hIconSm        = 0;

    RegisterClassEx(&wcex);

    DWORD style = WS_SYSMENU | WS_BORDER | WS_CAPTION |
        WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_MAXIMIZEBOX | WS_MINIMIZEBOX | WS_SIZEBOX;

    int windowWidth = 440;
    int windowHeight = 380;

    hWnd = CreateWindow( Win32ClassName, "Irrlicht Win32 window example",
        style, 100, 100, windowWidth, windowHeight,
        NULL, NULL, hInstance, NULL);

    RECT clientRect;
    GetClientRect(hWnd, &clientRect);
    windowWidth = clientRect.right;
    windowHeight = clientRect.bottom;

    // Crée un bouton 'OK'.

    hOKButton = CreateWindow("BUTTON", "OK - Close", WS_CHILD | WS_VISIBLE | BS_TEXT,
        windowWidth - 160, windowHeight - 40, 150, 30, hWnd, NULL, hInstance, NULL);

    // Crée du texte.

    CreateWindow("STATIC", "This is Irrlicht running inside a standard Win32 window.\n"\
        "Also mixing with MFC and .NET Windows.Forms is possible.",
        WS_CHILD | WS_VISIBLE, 20, 20, 400, 40, hWnd, NULL, hInstance, NULL);

    // Crée une fenêtre pour mettre Irrlicht dedans.

    HWND hIrrlichtWindow = CreateWindow("BUTTON", "",
            WS_CHILD | WS_VISIBLE | BS_OWNERDRAW,
            50, 80, 320, 220, hWnd, NULL, hInstance, NULL);
    video::SExposedVideoData videodata((key=='b')?hIrrlichtWindow:0);

II. Création du moteur Irrlicht

Ainsi, maintenant que nous avons une fenêtre, nous pouvons créer un moteur Irrlicht à l'intérieur. Nous utilisons pour cela la fonction createEx() d'Irrlicht. Nous avons uniquement besoin du gestionnaire (HWND) de cette fenêtre, de le mettre en tant que paramètre windowID et de démarrer le moteur comme d'habitude. Voilà, c'est tout.

 
Sélectionnez
    // Crée le moteur Irrlicht dans le bouton de la fenêtre.

    irr::SIrrlichtCreationParameters param;
    param.DriverType = driverType;
    if (key=='a')
        param.WindowId = reinterpret_cast<void*>(hIrrlichtWindow);

    irr::IrrlichtDevice* device = irr::createDeviceEx(param);
    if (!device)
        return 1;

    // Met en place une scène 3D simple.

    irr::scene::ISceneManager* smgr = device->getSceneManager();
    video::IVideoDriver* driver = device->getVideoDriver();

    if (driverType==video::EDT_OPENGL)
    {
        HDC HDc=GetDC(hIrrlichtWindow);
        PIXELFORMATDESCRIPTOR pfd={0};
        pfd.nSize=sizeof(PIXELFORMATDESCRIPTOR);
        int pf = GetPixelFormat(HDc);
        DescribePixelFormat(HDc, pf, sizeof(PIXELFORMATDESCRIPTOR), &pfd);
        pfd.dwFlags |= PFD_DOUBLEBUFFER | PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW;
        pfd.cDepthBits=16;
        pf = ChoosePixelFormat(HDc, &pfd);
        SetPixelFormat(HDc, pf, &pfd);
        videodata.OpenGLWin32.HDc = HDc;
        videodata.OpenGLWin32.HRc=wglCreateContext(HDc);
        wglShareLists((HGLRC)driver->getExposedVideoData().OpenGLWin32.HRc, (HGLRC)videodata.OpenGLWin32.HRc);
    }
    scene::ICameraSceneNode* cam = smgr->addCameraSceneNode();
    cam->setTarget(core::vector3df(0,0,0));

    scene::ISceneNodeAnimator* anim =
        smgr->createFlyCircleAnimator(core::vector3df(0,15,0), 30.0f);
    cam->addAnimator(anim);
    anim->drop();

    scene::ISceneNode* cube = smgr->addCubeSceneNode(20);

    cube->setMaterialTexture(0, driver->getTexture("../../media/wall.bmp"));
    cube->setMaterialTexture(1, driver->getTexture("../../media/water.jpg"));
    cube->setMaterialFlag( video::EMF_LIGHTING, false );
    cube->setMaterialType( video::EMT_REFLECTION_2_LAYER );

    smgr->addSkyBoxSceneNode(
    driver->getTexture("../../media/irrlicht2_up.jpg"),
    driver->getTexture("../../media/irrlicht2_dn.jpg"),
    driver->getTexture("../../media/irrlicht2_lf.jpg"),
    driver->getTexture("../../media/irrlicht2_rt.jpg"),
    driver->getTexture("../../media/irrlicht2_ft.jpg"),
    driver->getTexture("../../media/irrlicht2_bk.jpg"));

    // Montre et exécute la boîte de dialogue.

    ShowWindow(hWnd , SW_SHOW);
    UpdateWindow(hWnd);

    // Crée une queue de messages.

III. Boucle de rendu

Maintenant, la seule chose manquante est la boucle de rendu avec IrrlichtDevice::run(). Nous le faisons comme d'habitude. Mais au lieu de cela, il y a une autre possibilité : vous pouvez aussi utiliser votre propre boucle de messages en utilisant GetMessage, DispatchMessage ou n'importe quoi d'autre. Appeler Device->run(), fera qu'Irrlicht enverra aussi ses messages internes. Vous ne devez pas appeler Device->run() si vous voulez faire votre propre boucle d'envoi de messages, mais Irrlicht ne sera alors pas capable de rapporter les événements de l'utilisateur. Vous devez donc le faire vous-même en utilisant les messages de la fenêtre, DirectInput ou n'importe quoi d'autre.

 
Sélectionnez
    while (device->run())
    {
        driver->beginScene(true, true, 0, videodata);
        smgr->drawAll();
        driver->endScene();
    }

L'alternative avec votre propre boucle d'envoi de message sans Device->run() devrait ressembler à cela :

 
Sélectionnez
MSG msg;
while (true) {
     if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
     {
           TranslateMessage(&msg); DispatchMessage(&msg);
           if (msg.message == WM_QUIT) break;
     }
    advance virtual time device->getTimer()->tick();
    draw engine picture driver->beginScene(true, true, 0, (key=='c') ? hIrrlichtWindow:0);
         smgr->drawAll();
         driver->endScene();
    } 
    device->closeDevice();
    device->drop();

    return 0;
}
#endif // si Windows

Voilà, Irrlicht tourne maintenant dans votre propre fenêtre Windows.

IV. Conclusion

Vous pouvez désormais utiliser Irrlicht dans une fenêtre Windows.

Dans le prochain tutoriel Charger des scènes à partir de fichiers .irr, nous verrons comment sauvegarder et charger des scènes entières dans un fichier .irr.

V. Remerciements

Merci à Nikolaus Gebhardt de nous permettre de traduire ce tutoriel.

Merci à LittleWhite pour sa relecture technique ainsi qu'à ClaudeLELOUP pour sa relecture orthographique.