Tutorial 14 - Win32 Window - Chip - 19-08-2015
Tutorial 14: Win32 Window
Questo esempio gira solo su MS Windiws e dimostra come Irrlicht può produrre rendering dentro una finestra win32 originale. E' possibile anche farlo su finestre create con le librerie MFC e con le finestre Windows.Forms della libreria .NET.
All'inizio creiamo una finestra di Windows usando le API. Non spiegherò in dettaglio come funziona questo codice. Per maggiori approfondimenti si rimanda al sito MSDN o a testi specifici sulla programmazione di Windows.
Codice PHP: #include <irrlicht.h> #ifndef _IRR_WINDOWS_ #error Windows only example #else #include <windows.h> // this example only runs with 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); }
Ora chiediamo quale driver usare e creiamo una istanza della finestra Windows definita prima.
Codice PHP: int main() { // ask user for driver 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; // 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); video::SExposedVideoData videodata((key=='b')?hIrrlichtWindow:0);
Adesso che abbiamo la finestra aperta possiamo crearci dentro il nostro device Irrlicht. Per farlo usiamo la funzione di Irrlicht createEx(). Ci servono l'handle (HWND) a quella finestra, impostarla come parametro di windowsID e poi lanciare l'engine come al solito. Questo è tutto.
Codice PHP: // create irrlicht device in the button window
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;
// setup a simple 3d scene
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"));
// show and execute dialog
ShowWindow(hWnd , SW_SHOW); UpdateWindow(hWnd);
// do message queue
L'ultima cosa che manca è il loop del disegno tramite IrrlichtDevice::run(). Lo facciamo come di solito abbiamo fatto. Ma potremmo anche fare in un altro modo: semplicemente utilizzare un nostro loop di messaggi windows tramite GetMessage, DispatchMessage. Poiché richiamare Device->run() causa l'invio dei messaggi internamente a Irrlicht, non vi serve più richiamarlo. Considerate però che se vorrete farvi da soli il vostro loop per la messaggistica Windows, Irrlicht non potrà più gestire nemmeno gli input utente che dovrete quindi gestire da soli usando la messaggistica di Window, oppure con le DirectInput, o una qualsiasi altra soluzione alternativa.
Codice PHP: while (device->run()) { driver->beginScene(true, true, 0, videodata); smgr->drawAll(); driver->endScene(); }
In alternativa un proprio sistema di messaggistica interno senza l'uso della Device->run() potrebbe assomigliare a qualcosa del genere:
Codice PHP: 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 // if windows
Ed è tutto, ora Irrlicht gira dentro la vostra finestra Windows.
Versione pdf scaricabile da QUI
|