Tutorial 14: Win32 Window
This example only runs in Windows and demonstrates that Irrlicht
can run inside a win32 window. MFC and .NET Windows.Forms windows
are possible too.
The program which is described here will look like this:
|
| Lets start! |
In the begining, we create a windows window using the windows
API. I'm not going to explain this code, because it is windows
specific. See the MSDN or a windows book for details.
#include <irrlicht.h>
#include <windows.h> // this example only runs with windows
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);
}
int main()
//int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hpre, LPSTR cmd, int cc)
{
HINSTANCE hInstance = 0;
// create dialog
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;
// create ok button
hOKButton = CreateWindow(
"BUTTON", "OK - Close", WS_CHILD | WS_VISIBLE | BS_TEXT,
windowWidth - 160, windowHeight - 40, 150, 30, hWnd, NULL,
hInstance, NULL);
// create some text
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);
// create window to put irrlicht in
HWND hIrrlichtWindow = CreateWindow("BUTTON", "", WS_CHILD | WS_VISIBLE | BS_OWNERDRAW,
50, 80, 320, 220, hWnd, NULL, hInstance, NULL);
|
So now that we have some window, we can create an Irrlicht
device inside of it. We use Irrlicht createEx() function
for this. We only need the handle (HWND) to that window,
set it as windowsID parameter and start up the engine as
usual. That's it.
// create irrlicht device in the button window
irr::SIrrlichtCreationParameters param;
param.WindowId = reinterpret_cast(hIrrlichtWindow); // hColorButton
param.DriverType = video::EDT_OPENGL;
irr::IrrlichtDevice* device = irr::createDeviceEx(param);
// setup a simple 3d scene
irr::scene::ISceneManager* smgr = device->getSceneManager();
video::IVideoDriver* driver = device->getVideoDriver();
scene::ICameraSceneNode* cam = smgr->addCameraSceneNode();
cam->setTarget(core::vector3df(0,0,0));
scene::ISceneNodeAnimator* anim =
smgr->createFlyCircleAnimator(core::vector3df(0,10,0), 30.0f);
cam->addAnimator(anim);
anim->drop();
scene::ISceneNode* cube = smgr->addCubeSceneNode(25);
cube->setMaterialFlag(video::EMF_LIGHTING, false);
cube->setMaterialTexture(0, driver->getTexture("../../media/rockwall.bmp"));
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"));
// show and execute dialog
ShowWindow(hWnd , SW_SHOW);
UpdateWindow(hWnd);
|
Now the only thing missing is the drawing loop using IrrlichtDevice::run().
We do this as usual. But instead of this, there is another
possibility: You can also simply use your own message loop
using GetMessage, DispatchMessage and whatever. Calling
Device->run() will cause Irrlicht to dispatch messages
internally too. You need not call Device->run() if you
want to do your own message dispatching loop, but Irrlicht
will not be able to fetch user input then and you have to
do it on your own using the window messages, DirectInput,
or whatever.
while (device->run())
{
driver->beginScene(true, true, 0);
smgr->drawAll();
driver->endScene();
}
// the alternative, own message dispatching loop without Device->run() would
// look like this:
/*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);
smgr->drawAll();
driver->endScene();
}*/
device->closeDevice();
device->drop();
return 0;
} |
That's it, Irrlicht now runs in your own windows window.
|
|