I. Création de la fenêtre Windows▲
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.
#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.
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.
// 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.0
f);
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.
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 :
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.