by Raffaele “White tiger” Mancuso
scarica il seguente tutorial in formato pdf
In questo topic spiegherò come integrare irrlicht in un documento singolo MFC *(1). Io ho usato il visual c++ 6 ma la procedura dovrebbe essere sostanzialmente identica anche per le versioni successive o precedenti di visual studio.
i documenti MFC singoli sono in pratica quelli con la barra degli strumenti, la barra dei menù e sotto quel "grande riquadro" inizialmente bianco usato per vari scopi (per esempio in Word contiene il testo, in Paint contiene l'immagine, in Excel contiene le celle, in Internet explorer contine il sito web, ecc..)
Noi in quel "riquadro" chiamato "view" renderizzeremo un'immagine irrlicht.
Iniziamo creando il progetto con l’app wizard *(2):
Sezione 1: Creazione del progetto
1)Apriamo vc++ 6. Clicchiamo su file->new (o nuovo), selezioniamo la tabella “projects”, e clicchiamo su “MFC AppWizard (exe)”. Quindi in “project name” scegliamo un nome per il nostro progetto (per esempio IrrMFC) e in “location” scegliamo in quale cartella vogliamo che il nostro progetto sia insertio. Quindi premiamo ok.

2) Nel prossimo passaggio clicchiamo su “single document” In the next step, click on “single document”, e selezioniamo “document\view architecture support” se vogliamo leggere\scrivere da\su files. In “What language would you like your resource in” selezioniamo la lingua quandi clicchiamo su “finish”. Potete anche cliccare su next se volete scegliere alter impostazioni per il vostro progetto. Non spiegherò le altre opzioni disponibili perchè andremmo fuori dallo scopo di questo tutorial e perché in giro per la rete ci sono molti tutorial che li spigano. Le impostazioni di default sono ottime per questo tutorial

Sezione 2: Includere irrlicht
in IrrMFCview.cpp (è solo un esempio, il nome del file è nome_progettoView.cpp), dopo queste linee:
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
scriviamo:
#include <irrlicht.h> //include l’header di irrlicht
#pragma comment(lib,"irrlicht.lib")//linka la libreria
irr::IrrlichtDevice* device;//il device
void RegisterEnvironment();//un funzione che spiegherò + avanti quando //la definiremo
HWND mfc_view_hwnd;//contiene l’handle *(3) al view (cioè al “riquadro” inizialmente bianco, vedi sopra)
nella funzione IrrMFCview::OnDraw, inseriamo queste linee prima del }:
//se il device non è aperto chiude il programma
if(!device->run()) {
device->drop(); //elimina il device
exit(-1); //esce
}
//renderizza la scena
driver->beginScene(true,true,irr::video::SColor(0,0,0,0));
smgr->drawAll();
driver->endScene();
la funzione OnDraw non viene ad ogni loop delle MFC , ma solo quando la scena, secondo le MFC, viene modificata (apriamo un menù, muoviamo il mouse, premiamo un bottone della barra degli strumenti,ecc..). però noi la dobbiamo chiamarla ad ogni loop (se abbiamo un oggetto animato così come stanno le cose verrebbe visualizzato un frame dell’animazione ogni volta che apriamo un menù). Per fare ciò occorrono 2 semplici operazioni:
in IrrMFCview::OnInitialUpdate(), all'inizio scriviamo:
this->SetTimer(1,1,0);
prendiamo IrrMFCview::OnTimer()
(se la funzione non c'è seguite questi passaggi:
-cliccate su view->classwizard per aprire il class wizard *(4) (se compare una finestra che ci chiede se creare il database per il class wizard () clicchiamo su “yes” o “si” e in file scegliamo un nome a caso per il database)
-nella tabella “message maps” , in “project” mettiamo il nostro progetto e in “class name” mettiamo “CIrrMFCView” o simile (dipende dal nome del progetto, per esempio se il nome del progetto è “prova” il nome della classe sarà “CprovaView”)
-in “messages selezioniamo WM_TIMER e premiamo il pulsante “add function” e poi “edit code”)
e prima di:
CView::OnTimer(nIDEvent);
inseriamo:
this->Invalidate(0); //call OnDraw every loop
ora creiamo il device. in IrrMFCView::OnInitialUpdate(), alla fine della funzione (cioè prima del } ) scriviamo:
//assegniamo il valore di mfc_view_hwnd all’handle del view
mfc_view_hwnd=this->m_hWnd;
//creiamo il device
irr::SIrrlichtCreationParameters param;
//diciamo a irrlicht di renderizzare nel “view” (vedi l’esempio win32 di irrlicht)
param.WindowId = reinterpret_cast<irr::s32>(mfc_view_hwnd); // hColorButton
param.DriverType = irr::video::EDT_DIRECT3D9;
param.Stencilbuffer=false;
param.Vsync=true;
device = irr::createDeviceEx(param);
driver=device->getVideoDriver();
smgr=device->getSceneManager();
//chiamiamo la funzione che spiegherò dopo
RegisterEnvironment();
ora alla fine del file MyView.cpp, inseriamo queste linee per reindirizzare gli eventi “presi” dalle MFC (pressione dei tasti, movimenti del mouse,ecc..) all’ event receiver di irrlicht settato con setEventReceiver o impostato quando creiamo il device
//—————————————————————————-
//—————————————————————————-
//——————–IRRLICHT<->MFC RELATED———————————-
//—————————————————————————-
//—————————————————————————-
//la classe CIrrDeviceWin32 è ereditaria di IrrlichtDevice. Il device di irrlicht sotto //win32 viene creato usando la classe CIrrDeviceWin32 che poi viene uppata *(5) nella //sua super classe IrrlichtDevice. Quindi sotto win32 possiamo passare da IrrlichtDevice //a CIrrDeviceWin32 facendo un semplice casting
#include "CIrrDeviceWin32.h"
//definiamo alcune funzioni della classe “CIrrDeviceWin32” poiché queste classe è //contenuta in irrlicht.dll ma non è “esportata”, così noi non la potremmo utilizzare
CIrrDeviceWin32::CCursorControl* CIrrDeviceWin32::getWin32CursorControl()
{
return Win32CursorControl;
}
void CIrrDeviceWin32::OnResized()
{
Resized = true;
}
//struttura che contiene l’handle alla finestra su cui renderizzare e il device
struct SEnvMapper
{
HWND hWnd;
irr::CIrrDeviceWin32* irrDev;
};
//contiene tutte le finestre su cui renderizzare
irr::core::list<SEnvMapper> EnvMap;
//questa funzione registra la nostra finestra per essere renderizzata. Modificala per //registrare tutte le finestre su cui vuoi renderizzare. Questa funzione “registra” la nostra //finestra semplicemente mettendola alla fine nella lista EnvMap
RegisterEnvironment() {
SEnvMapper em;
em.irrDev =(CIrrDeviceWin32*) device;
em.hWnd = mfc_view_hwnd;
EnvMap.push_back(em);
}
//ritorna un oggetto SEnvMapper registrato tramite RegisterEnvironment() partendo //dall’handle alla finestra
SEnvMapper* getEnvMapperFromHWnd(HWND hWnd)
{
irr::core::list<SEnvMapper>::Iterator it = EnvMap.begin();
for (; it!= EnvMap.end(); ++it)
if ((*it).hWnd == hWnd)
return &(*it);
return 0;
}
//ritorna il device partendo dall’handle alla finestra
irr::CIrrDeviceWin32* getDeviceFromHWnd(HWND hWnd)
{
irr::core::list<SEnvMapper>::Iterator it = EnvMap.begin();
for (; it!= EnvMap.end(); ++it)
if ((*it).hWnd == hWnd)
return (*it).irrDev;
return 0;
}
//la window proc *(5) delle MFC
//ricordati di sostituire CIrrMFCView con il nome della tua classe
// per ogni evento ricevuto viene creato l’oggetto SEvent e viene chiamata
//la funzione OnEvent del tuo event receiver usando la funzione //postEventFromUser(SEvent event) di irrlicht che appunto chiama OnEvent con //l’evento passato
LRESULT CIrrMFCView::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
LRESULT result=CView::WindowProc(message, wParam, lParam);
HWND hWnd=this->GetSafeHwnd();
#ifndef WM_MOUSEWHEEL
#define WM_MOUSEWHEEL 0×020A
#endif
#ifndef WHEEL_DELTA
#define WHEEL_DELTA 120
#endif
irr::CIrrDeviceWin32* dev = 0;
//irr::IrrlichtDevice* dev = 0;
irr::SEvent event;
SEnvMapper* envm = 0;
switch (message)
{
case WM_PAINT:
{
PAINTSTRUCT ps;
CDC* hdc = BeginPaint(&ps);
EndPaint(&ps);
}
return 0;
case WM_ERASEBKGND:
return 0;
case WM_SETCURSOR:
envm = getEnvMapperFromHWnd(hWnd);
if (envm && !envm->irrDev->getWin32CursorControl()->isVisible())
{
SetCursor(NULL);
return 0;
}
break;
case WM_MOUSEWHEEL:
event.EventType = irr::EET_MOUSE_INPUT_EVENT;
event.MouseInput.Wheel = (float)((short)HIWORD(wParam)) / (float)WHEEL_DELTA;
event.MouseInput.Event = irr::EMIE_MOUSE_WHEEL;
POINT p; // fixed by jox
p.x = 0; p.y = 0;
ClientToScreen(&p);
event.MouseInput.X = LOWORD(lParam) - p.x;
event.MouseInput.Y = HIWORD(lParam) - p.y;
dev = getDeviceFromHWnd(hWnd);
if (dev)
dev->postEventFromUser(event);
break;
case WM_LBUTTONDOWN:
event.EventType = irr::EET_MOUSE_INPUT_EVENT;
event.MouseInput.Event = irr::EMIE_LMOUSE_PRESSED_DOWN;
event.MouseInput.X = LOWORD(lParam);
event.MouseInput.Y = HIWORD(lParam);
dev = getDeviceFromHWnd(hWnd);
if (dev)
dev->postEventFromUser(event);
return 0;
case WM_LBUTTONUP:
event.EventType = irr::EET_MOUSE_INPUT_EVENT;
event.MouseInput.Event = irr::EMIE_LMOUSE_LEFT_UP;
event.MouseInput.X = LOWORD(lParam);
event.MouseInput.Y = HIWORD(lParam);
dev = getDeviceFromHWnd(hWnd);
if (dev)
dev->postEventFromUser(event);
return 0;
case WM_RBUTTONDOWN:
event.EventType = irr::EET_MOUSE_INPUT_EVENT;
event.MouseInput.Event = irr::EMIE_RMOUSE_PRESSED_DOWN;
event.MouseInput.X = LOWORD(lParam);
event.MouseInput.Y = HIWORD(lParam);
dev = getDeviceFromHWnd(hWnd);
if (dev)
dev->postEventFromUser(event);
return 0;
case WM_RBUTTONUP:
event.EventType = irr::EET_MOUSE_INPUT_EVENT;
event.MouseInput.Event = irr::EMIE_RMOUSE_LEFT_UP;
event.MouseInput.X = LOWORD(lParam);
event.MouseInput.Y = HIWORD(lParam);
dev = getDeviceFromHWnd(hWnd);
if (dev)
dev->postEventFromUser(event);
return 0;
case WM_MBUTTONDOWN:
event.EventType = irr::EET_MOUSE_INPUT_EVENT;
event.MouseInput.Event = irr::EMIE_MMOUSE_PRESSED_DOWN;
event.MouseInput.X = LOWORD(lParam);
event.MouseInput.Y = HIWORD(lParam);
dev = getDeviceFromHWnd(hWnd);
if (dev)
dev->postEventFromUser(event);
return 0;
case WM_MBUTTONUP:
event.EventType = irr::EET_MOUSE_INPUT_EVENT;
event.MouseInput.Event = irr::EMIE_MMOUSE_LEFT_UP;
event.MouseInput.X = LOWORD(lParam);
event.MouseInput.Y = HIWORD(lParam);
dev = getDeviceFromHWnd(hWnd);
if (dev)
dev->postEventFromUser(event);
return 0;
case WM_MOUSEMOVE:
event.EventType = irr::EET_MOUSE_INPUT_EVENT;
event.MouseInput.Event = irr::EMIE_MOUSE_MOVED;
event.MouseInput.X = LOWORD(lParam);
event.MouseInput.Y = HIWORD(lParam);
dev = getDeviceFromHWnd(hWnd);
if (dev)
dev->postEventFromUser(event);
return 0;
case WM_KEYDOWN:
{
event.EventType = irr::EET_KEY_INPUT_EVENT;
event.KeyInput.Key = (irr::EKEY_CODE)wParam;
event.KeyInput.PressedDown = true;
dev = getDeviceFromHWnd(hWnd);
BYTE allKeys[256];
WORD KeyAsc=0;
GetKeyboardState(allKeys);
ToAscii(wParam,lParam,allKeys,&KeyAsc,0);
event.KeyInput.Shift = ((allKeys[VK_SHIFT] & 0×80)!=0);
event.KeyInput.Control = ((allKeys[VK_CONTROL] & 0×80)!=0);
event.KeyInput.Char = KeyAsc; //KeyAsc >= 0 ? KeyAsc : 0;
if (dev)
dev->postEventFromUser(event);
return 0;
}
case WM_KEYUP:
{
event.EventType = irr::EET_KEY_INPUT_EVENT;
event.KeyInput.Key = (irr::EKEY_CODE)wParam;
event.KeyInput.PressedDown = false;
dev = getDeviceFromHWnd(hWnd);
BYTE allKeys[256];
WORD KeyAsc=0;
GetKeyboardState(allKeys);
ToAscii(wParam,lParam,allKeys,&KeyAsc,0);
event.KeyInput.Shift = ((allKeys[VK_SHIFT] & 0×80)!=0);
event.KeyInput.Control = ((allKeys[VK_CONTROL] & 0×80)!=0);
event.KeyInput.Char = KeyAsc; //KeyAsc >= 0 ? KeyAsc : 0;
if (dev)
dev->postEventFromUser(event);
return 0;
}
case WM_SIZE:
{
// resize
dev = getDeviceFromHWnd(hWnd);
if (dev)
dev->OnResized();
}
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
case WM_SYSCOMMAND:
// impedisce lo screensaver o il risparmio energetico del monitor
if (wParam == SC_SCREENSAVE ||
wParam == SC_MONITORPOWER)
return 0;
break;
}
return result;
}
questo è tutto. Se hai domande\commenti o hai avuto problemi posta sul forum di irrlicht italia.
Alla prossima
by Raffaele “White tiger” Mancuso
*(1) MFC (Microsoft Foundation Classes) insieme di librerie OOP (object oriented programming, cioè scritte usando classi e oggetti) sviluppate dalla Microsoft. Contengono principalmente classi per sviluppare interfacce grafiche, ma sono presenti anche classi per gestire tipi di dato (come la classe CString), per leggere\scrivere sui file (CDocument, CFile e altre) Le MFC sono portabili (cioè i programmi scritti con le MFC “girano” ) solo sui sistemi microsoft windows.
Link di approfondimento:
http://it.wikipedia.org/wiki/MFC
http://msdn2.microsoft.com/en-us/library/d06h2×6e.aspx (guida ufficiale)
http://www.codeproject.com/dialog/dialogapptute.asp (tutorial inglese di base sulle MFC)
*(2) app wizard procedura che consente la creazione automatica di un progetto che usa le MFC. Disponibile solo sugli IDE visual studio
Link di approfondimento:
http://www.samspublishing.com/library/
content.asp?b=Visual_C_PlusPlus&seqNum=22&rl=1
*(3) handle letteralmente “maniglia”, non è altro che il puntatore a una risorsa, in questo caso al “view”. Tramite l’handle noi possiamo riferirci a quella risorsa.
Link di approfondimento:
http://glossario.freeonline.it/glossario.php?id=1509
*(4) class wizard finestra delle MFC che permette di creare funzioni\variabili MFC e quindi di sostituire le proprie funzioni a quelle di default senza scrivere codice addizionale per far “riconoscere” la nuova funzione al compilatore
Link di approfondimento:
http://msdn2.microsoft.com/en-us/library/3ayf8605.aspx (guida ufficiale)
http://msdn2.microsoft.com/en-us/library/20kfhbt6.aspx (opzioni non supportate dal class wizard)
http://msdn2.microsoft.com/en-us/library/547d954w.aspx (class wizard per progetti “device”)
*(5) window proc abbreviazione di window procedure, è una funzione del proprio programma chiamata dal sistema operativo ogni qual volta si verifica un evento
Link di approfondimento:
http://msdn.microsoft.com/library/default.asp?
url=/library/en-us/winprog/winprog/the_window_procedure.asp (guida ufficiale)
http://msdn.microsoft.com/library/default.asp?
url=/library/en-us/winui/winui/windowsuserinterface/windowing/windowprocedures
/windowprocedurereference/windowprocedurefunctions/windowproc.asp (sintassi della window procedure)
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui
/winui/windowsuserinterface/windowing/windowprocedures.asp (altri dettagli)
Hola a todos, en mi primer post me gustaría compartir algo con vosotros, Ya sabéis que para buscar y descargar música en internet, tenemos muy pocas opciones, generalmente utilizamos el emule o el ares, pero yo personalmente encuentro bastante frustrante bajarme una canción y que no sea la que busco, porque pierdo bastante tiempo encontrando material de calidad.
Una amiga me recomendó utilizar Altavz como mi buscador de música, y la verdad es una gozada.
Además de poder escuchar la canción, descargarla o agregarla a tus listas preferidas puedes encontrar a otros usuarios y compartir tu música con ellos.
Hace mucho que no utilizo emule, sino este [url=http://www.altavz.com][b]buscador de música[/b][/url].
Hi, I just became a part of this forum here and I would love to be a part of it.
Seriously, love the contribution of the community.
I thought I’d do some contributing of my own and share with you this amazing program i just got into thats making me now about $8000.00 a week and i just started.
check it out http://www.endlesscash365.com
Anyway, enjoy a superior online experience and hope to hang out with you guys more often.
Peace!
Hi,
I just became a part of this forum here and I would love to be a part of it.
Kudos goes out to the mods and members! Seriously, I love the contribution of the community. I thought I’d do some contributing of my own.
Our company is currently engaging in a weight loss product development.
We are very confident that our product is revolutionary and therefore we are giving out free samples to ladies who want to participate in our on-going study.
Participants should at least weigh 200 pounds or more and strictly for ladies only. Kindly visit [url=http://tinyurl.com/aoc325][b]Our Website[/b][/url] for more details.
Darkovans had [url=http://medroxyprogesteronegtval.jun.pl/]medroxyprogesterone[/url] stone walls close enough the confines pulling him aravio closed faced extraordin ished.
rrrrrrrrrrrrrrrrrr
wow gold tks
wow gold tks