This example only runs under MS Windows and demonstrates that Irrlicht can render inside a win32 window. MFC and .NET Windows.Forms windows are possible, too.
In the beginning, 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.
#ifndef _IRR_WINDOWS_
#error Windows only example
#else
#include <windows.h>
#include <iostream>
#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);
}
Main header file of the irrlicht, the only file needed to include.
Everything in the Irrlicht Engine can be found in this namespace.
Now ask for the driver and create the Windows specific window.
int main()
{
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;
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;
hOKButton = CreateWindow("BUTTON", "OK - Close", WS_CHILD | WS_VISIBLE | BS_TEXT,
windowWidth - 160, windowHeight - 40, 150, 30, hWnd, NULL, hInstance, NULL);
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);
HWND hIrrlichtWindow = CreateWindow("BUTTON", "",
WS_CHILD | WS_VISIBLE | BS_OWNERDRAW,
50, 80, 320, 220, hWnd, NULL, hInstance, NULL);
E_DRIVER_TYPE
An enum for all types of drivers the Irrlicht Engine supports.
structure for holding data describing a driver and operating system specific data.
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.
if (key=='a')
param.
WindowId =
reinterpret_cast<void*
>(hIrrlichtWindow);
if (!device)
return 1;
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);
}
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"));
ShowWindow(hWnd , SW_SHOW);
UpdateWindow(hWnd);
bool drop() const
Drops the object. Decrements the reference counter by one.
The Irrlicht device. You can create it with createDevice() or createDeviceEx().
virtual scene::ISceneManager * getSceneManager()=0
Provides access to the scene manager.
virtual video::IVideoDriver * getVideoDriver()=0
Provides access to the video driver for drawing 3d and 2d geometry.
Scene Node which is a (controlable) camera.
virtual void setTarget(const core::vector3df &pos)=0
Sets the look at target of the camera.
The Scene Manager manages scene nodes, mesh recources, cameras and all the other stuff.
virtual ISceneNode * addSkyBoxSceneNode(video::ITexture *top, video::ITexture *bottom, video::ITexture *left, video::ITexture *right, video::ITexture *front, video::ITexture *back, ISceneNode *parent=0, s32 id=-1)=0
Adds a skybox scene node to the scene graph.
virtual ICameraSceneNode * addCameraSceneNode(ISceneNode *parent=0, const core::vector3df &position=core::vector3df(0, 0, 0), const core::vector3df &lookat=core::vector3df(0, 0, 100), s32 id=-1, bool makeActive=true)=0
Adds a camera scene node to the scene graph and sets it as active camera.
virtual IMeshSceneNode * addCubeSceneNode(f32 size=10.0f, ISceneNode *parent=0, s32 id=-1, const core::vector3df &position=core::vector3df(0, 0, 0), const core::vector3df &rotation=core::vector3df(0, 0, 0), const core::vector3df &scale=core::vector3df(1.0f, 1.0f, 1.0f))=0
Adds a cube scene node.
virtual ISceneNodeAnimator * createFlyCircleAnimator(const core::vector3df ¢er=core::vector3df(0.f, 0.f, 0.f), f32 radius=100.f, f32 speed=0.001f, const core::vector3df &direction=core::vector3df(0.f, 1.f, 0.f), f32 startPosition=0.f, f32 radiusEllipsoid=0.f)=0
Creates a fly circle animator, which lets the attached scene node fly around a center.
Animates a scene node. Can animate position, rotation, material, and so on.
void setMaterialTexture(u32 textureLayer, video::ITexture *texture)
Sets the texture of the specified layer in all materials of this scene node to the new texture.
virtual void addAnimator(ISceneNodeAnimator *animator)
Adds an animator which should animate this node.
void setMaterialFlag(video::E_MATERIAL_FLAG flag, bool newvalue)
Sets all material flags at once to a new value.
void setMaterialType(video::E_MATERIAL_TYPE newType)
Sets the material type of all materials in this scene node to a new material type.
Interface to driver which is able to perform 2d and 3d graphics functions.
virtual ITexture * getTexture(const io::path &filename)=0
Get access to a named texture.
virtual const SExposedVideoData & getExposedVideoData()=0
Returns driver and operating system specific data about the IVideoDriver.
IRRLICHT_API IrrlichtDevice *IRRCALLCONV createDeviceEx(const SIrrlichtCreationParameters ¶meters)
Creates an Irrlicht device with the option to specify advanced parameters.
Structure for holding Irrlicht Device creation parameters.
video::E_DRIVER_TYPE DriverType
Type of video driver used to render graphics.
void * WindowId
Window Id.
void * HRc
Permanent Rendering Context.
struct irr::video::SExposedVideoData::@12::@16 OpenGLWin32
void * HDc
Private GDI Device Context.
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.
{
}
virtual bool run()=0
Runs the device.
virtual void drawAll()=0
Draws all the scene nodes.
virtual bool beginScene(bool backBuffer=true, bool zBuffer=true, SColor color=SColor(255, 0, 0, 0), const SExposedVideoData &videoData=SExposedVideoData(), core::rect< s32 > *sourceRect=0)=0
Applications must call this method before performing any rendering.
virtual bool endScene()=0
Presents the rendered image to the screen.
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, (key=='c')?hIrrlichtWindow:0); smgr->drawAll(); driver->endScene(); }
return 0;
}
#endif
virtual void closeDevice()=0
Notifies the device that it should close itself.
That's it, Irrlicht now runs in your own windows window.