19-08-2015, 08:53 PM
Tutorial 17: Helloworld mobile
Questo esempio mostra il classico Hello World in versione per Windows mobile. Compila anche per altre piattaforme. La sola differenza dall'esempio originale è che qui vi serve una GUI, per permettere come minimo di uscire dall'app e un Filesystem, perché cambia in quanto è relativo alla singola piattaforma dell'eseguibile.
Avviamo lo Startup per il nostro Windows Mobile Device
L'avvio della funzione main è analogo a quello degli altri esempi. Chiediamo all'utente quale renderer desideri usare e lo avviamo. Stavolta gestiamo anche i parametri avanzati.
Primo, aggiungiamo le classiche cose nella scena: Un logo di irrlicht, un piccolo testo di aiuto, una camera controllata dall'utente ed disabilitiamo il cursore del mouse.
Ecco il nodo di scena per il tereno: lo aggiungiamo come un qualsiasi altro nodo di scena usando ISceneManager::addTerrainSceneNode(). L'unico parametro che usiamo è il nome del file della heightmap usata. Una heightmap è una semplice texture a scale di grigi. Il nodo la caricherà e ci creerà un terreno 3D.
Per rendere il terreno più grande cambiamo i valori di scala a (40, 4.4, 40). Poiché non abbiamo nessuna luce dinamica nella scena disabilitiamo l'illuminazione, impostiamo il file terrain-texture.jpg come texture principale e detailmap3.jpg come texture secondaria, per i dettagli. Per ultimo impostiamo i valori di scala per le texture, la prima la ripetiamo una sola volta in modo che copra tutto il terreno esattamente, la seconda la riduciamo in modo che si ripeta sul terreno per 20 volte.
Per abilitare le collisioni con il terreno creiamo un triangle selector. Se volete conoscere cosa fanno i triangle selectors date un'occhiata al tutorial delle collisioni. Il terrain triangle selector lavora insieme al terreno. Per dimostrarlo creiamo un collision response animator e attacchiamolo alla camera, in modo da impedire alla camera di attraversa il terreno stesso.
Se vi serve accedere ai dati del terreno lo potete fare con la seguente porzione di codice.
Per permettere all'utente di cambiare tra la modalità wireframe e la normale creiamo un'istanza di event receiver e indichiamolo ad Irrlicht. In più aggiungiamo uno skybox già usato in molti altri esempi e uno skydome, da poter commutare tra loro mediante il tasto 'S'.
Per rendere la mesh più carina cambiamo il suo materiae. Disabilitiamo l'illuminazione perché tanto non abbiamo luci dinamiche, altrimenti diventerebbe tutta nera. Quindi impostiamo il loop sul frame dell'animazione a quello predefinito STAND. E per ultimo applichiamo la texture alla mesh. Senza di essa la mesh verrebbe mostrata monocolore.
Per avere, da subito, lo sguardo rivolto alla nostra mesh piazziamo la camera nello spazio 3d in posizione (0, 30, -40). Da qui la camera è girata verso la direzione (0,5,0), che è approssimativamente il punto dove si trova il nostro modello md2.
Versione scaricabile da QUI
Questo esempio mostra il classico Hello World in versione per Windows mobile. Compila anche per altre piattaforme. La sola differenza dall'esempio originale è che qui vi serve una GUI, per permettere come minimo di uscire dall'app e un Filesystem, perché cambia in quanto è relativo alla singola piattaforma dell'eseguibile.
Codice PHP:
#include <irrlicht.h>
#if defined ( _IRR_WINDOWS_ )
#include <windows.h>
#endif
using namespace irr;
using namespace core;
using namespace scene;
using namespace video;
using namespace io;
using namespace gui;
#pragma comment(lib, "Irrlicht.lib")
class EventReceiver_basic : public IEventReceiver
{
private:
IrrlichtDevice *Device;
public:
EventReceiver_basic ( IrrlichtDevice *device ): Device ( device ) {}
virtual bool OnEvent(const SEvent& event)
{
if (event.EventType == EET_GUI_EVENT)
{
s32 id = event.GUIEvent.Caller->getID();
switch(event.GUIEvent.EventType)
{
case EGET_BUTTON_CLICKED:
if (id == 2)
{
Device->closeDevice();
return true;
} break;
}
}
return false;
}
};
class CSampleSceneNode : public ISceneNode
{
aabbox3d<f32> Box;
S3DVertex Vertices[4];
SMaterial Material;
public:
CSampleSceneNode(ISceneNode* parent, ISceneManager* mgr, s32 id)
: ISceneNode(parent, mgr, id)
{
Material.Wireframe = false;
Material.Lighting = false;
Vertices[0] = S3DVertex(0,0,10, 1,1,0, SColor(255,0,255,255), 0, 1);
Vertices[1] = S3DVertex(10,0,-10, 1,0,0, SColor(255,255,0,255), 1, 1);
Vertices[2] = S3DVertex(0,20,0, 0,1,1, SColor(255,255,255,0), 1, 0);
Vertices[3] = S3DVertex(-10,0,-10, 0,0,1, SColor(255,0,255,0), 0, 0);
Box.reset(Vertices[0].Pos);
for (s32 i=1; i<4; ++i)
Box.addInternalPoint(Vertices[i].Pos);
}
virtual void OnRegisterSceneNode()
{
if (IsVisible)
SceneManager->registerNodeForRendering(this);
ISceneNode::OnRegisterSceneNode();
}
virtual void render()
{
u16 indices[] = { 0,2,3, 2,1,3, 1,0,3, 2,0,1 };
IVideoDriver* driver = SceneManager->getVideoDriver();
driver->setMaterial(Material);
driver->setTransform(ETS_WORLD, AbsoluteTransformation);
driver->drawIndexedTriangleList(&Vertices[0], 4, &indices[0], 4);
}
virtual const aabbox3d<f32>& getBoundingBox() const
{
return Box;
}
virtual u32 getMaterialCount()
{
return 1;
}
virtual SMaterial& getMaterial(u32 i)
{
return Material;
}
};
Codice PHP:
IrrlichtDevice *startup()
{
// both software and burnings video can be used
E_DRIVER_TYPE driverType = EDT_SOFTWARE; // EDT_BURNINGSVIDEO;
// create device
IrrlichtDevice *device = 0;
#if defined (_IRR_USE_WINDOWS_CE_DEVICE_)
// set to standard mobile fullscreen 240x320
device = createDevice(driverType, dimension2d<u32>(240, 320), 16, true );
#else
// on PC. use window mode
device = createDevice(driverType, dimension2d<u32>(240, 320), 16, false );
#endif
if ( 0 == device )
return 0;
IVideoDriver* driver = device->getVideoDriver();
ISceneManager* smgr = device->getSceneManager();
IGUIEnvironment* guienv = device->getGUIEnvironment();
// set the filesystem relative to the executable
#if defined (_IRR_WINDOWS_)
{
wchar_t buf[255];
GetModuleFileNameW ( 0, buf, 255 );
io::path base = buf;
base = base.subString ( 0, base.findLast ( '\\' ) + 1 );
device->getFileSystem()->addFileArchive ( base );
}
#endif
IGUIStaticText *text = guienv->addStaticText(L"FPS: 25",
rect<s32>(140,15,200,30), false, false, 0, 100 );
guienv->addButton(core::rect<int>(200,10,238,30), 0, 2, L"Quit");
// add irrlicht logo
guienv->addImage(driver->getTexture("../../media/irrlichtlogo3.png"),
core::position2d<s32>(0,-2));
return device;
}
!
int run ( IrrlichtDevice *device )
{
while(device->run())
if (device->isWindowActive())
{
device->getVideoDriver()->beginScene(true, true, SColor(0,100,100,100));
device->getSceneManager()->drawAll();
device->getGUIEnvironment()->drawAll();
device->getVideoDriver()->endScene ();
IGUIElement *stat = device->getGUIEnvironment()->
getRootGUIElement()->getElementFromId ( 100 );
if ( stat )
{
stringw str = L"FPS: ";
str += (s32)device->getVideoDriver()->getFPS();
stat->setText ( str.c_str() );
}
}
device->drop();
return 0;
}
!
int example_customscenenode()
{
// create device
IrrlichtDevice *device = startup();
if (device == 0)
return 1; // could not create selected driver.
// create engine and camera
EventReceiver_basic receiver(device);
device->setEventReceiver(&receiver);
IVideoDriver* driver = device->getVideoDriver();
ISceneManager* smgr = device->getSceneManager();
IGUIEnvironment* guienv = device->getGUIEnvironment();
smgr->addCameraSceneNode(0, vector3df(0,-40,0), vector3df(0,0,0));
CSampleSceneNode *myNode =
new CSampleSceneNode(smgr->getRootSceneNode(), smgr, 666);
ISceneNodeAnimator* anim =
smgr->createRotationAnimator(vector3df(0.8f, 0, 0.8f));
if(anim)
{
myNode->addAnimator(anim);
anim->drop();
anim = 0; // As I shouldn't refer to it again, ensure that I can't
}
myNode->drop();
myNode = 0; // As I shouldn't refer to it again, ensure that I can't
return run ( device );
}
class EventReceiver_terrain : public IEventReceiver
{
public:
EventReceiver_terrain(IrrlichtDevice *device, scene::ISceneNode* terrain, scene::ISceneNode* skybox, scene::ISceneNode* skydome) :
Device ( device ), Terrain(terrain), Skybox(skybox), Skydome(skydome), showBox(true)
{
Skybox->setVisible(true);
Skydome->setVisible(false);
}
bool OnEvent(const SEvent& event)
{
if (event.EventType == EET_GUI_EVENT)
{
s32 id = event.GUIEvent.Caller->getID();
switch(event.GUIEvent.EventType)
{
case EGET_BUTTON_CLICKED:
if (id == 2)
{
Device->closeDevice();
return true;
} break;
}
}
// check if user presses the key 'W' or 'D'
if (event.EventType == irr::EET_KEY_INPUT_EVENT && !event.KeyInput.PressedDown)
{
switch (event.KeyInput.Key)
{
case irr::KEY_KEY_W: // switch wire frame mode
Terrain->setMaterialFlag(video::EMF_WIREFRAME,
!Terrain->getMaterial(0).Wireframe);
Terrain->setMaterialFlag(video::EMF_POINTCLOUD, false);
return true;
case irr::KEY_KEY_P: // switch wire frame mode
Terrain->setMaterialFlag(video::EMF_POINTCLOUD,
!Terrain->getMaterial(0).PointCloud);
Terrain->setMaterialFlag(video::EMF_WIREFRAME, false);
return true;
case irr::KEY_KEY_D: // toggle detail map
Terrain->setMaterialType(
Terrain->getMaterial(0).MaterialType == video::EMT_SOLID ?
video::EMT_DETAIL_MAP : video::EMT_SOLID);
return true;
case irr::KEY_KEY_S: // toggle skies
showBox=!showBox;
Skybox->setVisible(showBox);
Skydome->setVisible(!showBox);
return true;
default:
break;
}
}
return false;
}
private:
IrrlichtDevice *Device;
scene::ISceneNode* Terrain;
scene::ISceneNode* Skybox;
scene::ISceneNode* Skydome;
bool showBox;
};
Codice PHP:
int example_terrain()
{
// create device
IrrlichtDevice *device = startup();
if (device == 0)
return 1; // could not create selected driver.
Codice PHP:
video::IVideoDriver* driver = device->getVideoDriver();
scene::ISceneManager* smgr = device->getSceneManager();
gui::IGUIEnvironment* env = device->getGUIEnvironment();
//set other font
//env->getSkin()->setFont(env->getFont("../../media/fontlucida.png"));
// add some help text
env->addStaticText(
L"Press 'W' to change wireframe mode\nPress 'D' to toggle detail map\nPress 'S' to toggle skybox/skydome",
core::rect<s32>(5,250,235,320), true, true, 0, -1, true);
// add camera
scene::ICameraSceneNode* camera =
smgr->addCameraSceneNodeFPS(0,100.0f,1.2f);
camera->setPosition(core::vector3df(2700*2,255*2,2600*2));
camera->setTarget(core::vector3df(2397*2,343*2,2700*2));
camera->setFarValue(42000.0f);
// disable mouse cursor
device->getCursorControl()->setVisible(false);
Per rendere il terreno più grande cambiamo i valori di scala a (40, 4.4, 40). Poiché non abbiamo nessuna luce dinamica nella scena disabilitiamo l'illuminazione, impostiamo il file terrain-texture.jpg come texture principale e detailmap3.jpg come texture secondaria, per i dettagli. Per ultimo impostiamo i valori di scala per le texture, la prima la ripetiamo una sola volta in modo che copra tutto il terreno esattamente, la seconda la riduciamo in modo che si ripeta sul terreno per 20 volte.
Codice PHP:
// add terrain scene node
scene::ITerrainSceneNode* terrain = smgr->addTerrainSceneNode(
"../../media/terrain-heightmap.bmp",
0, // parent node
-1, // node id
core::vector3df(0.f, 0.f, 0.f), // position
core::vector3df(0.f, 0.f, 0.f), // rotation
core::vector3df(40.f, 4.4f, 40.f), // scale
video::SColor ( 255, 255, 255, 255 ), // vertexColor
5, // maxLOD
scene::ETPS_17, // patchSize
4 // smoothFactor
);
if ( terrain )
{
terrain->setMaterialFlag(video::EMF_LIGHTING, false);
terrain->setMaterialTexture(0,
driver->getTexture("../../media/terrain-texture.jpg"));
terrain->setMaterialTexture(1,
driver->getTexture("../../media/detailmap3.jpg"));
terrain->setMaterialType(video::EMT_DETAIL_MAP);
terrain->scaleTexture(1.0f, 20.0f);
//terrain->setDebugDataVisible ( true );
Codice PHP:
// create triangle selector for the terrain
scene::ITriangleSelector* selector
= smgr->createTerrainTriangleSelector(terrain, 0);
terrain->setTriangleSelector(selector);
// create collision response animator and attach it to the camera
scene::ISceneNodeAnimator* anim = smgr->createCollisionResponseAnimator(
selector, camera, core::vector3df(60,100,60),
core::vector3df(0,0,0),
core::vector3df(0,50,0));
selector->drop();
camera->addAnimator(anim);
anim->drop();
Codice PHP:
scene::CDynamicMeshBuffer* buffer = new scene::CDynamicMeshBuffer(video::EVT_2TCOORDS, video::EIT_16BIT);
terrain->getMeshBufferForLOD(*buffer, 0);
video::S3DVertex2TCoords* data = (video::S3DVertex2TCoords*)buffer->getVertexBuffer().getData();
// Work on data or get the IndexBuffer with a similar call.
buffer->drop(); // When done drop the buffer again.
}
Codice PHP:
// create skybox and skydome
driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, false);
scene::ISceneNode* skybox=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"));
scene::ISceneNode* skydome=smgr->addSkyDomeSceneNode(driver->getTexture("../../media/skydome.jpg"),16,8,0.95f,2.0f);
driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, true);
// create event receiver
EventReceiver_terrain receiver( device, terrain, skybox, skydome);
device->setEventReceiver(&receiver);
return run ( device );
}
int example_helloworld()
{
// create device
IrrlichtDevice *device = startup();
if (device == 0)
return 1; // could not create selected driver.
IVideoDriver* driver = device->getVideoDriver();
ISceneManager* smgr = device->getSceneManager();
IGUIEnvironment* guienv = device->getGUIEnvironment();
IAnimatedMesh* mesh = smgr->getMesh("../../media/sydney.md2");
if (!mesh)
{
device->drop();
return 1;
}
IAnimatedMeshSceneNode* node = smgr->addAnimatedMeshSceneNode( mesh );
Codice PHP:
if (node)
{
node->setMaterialFlag(EMF_LIGHTING, false);
node->setMD2Animation(scene::EMAT_STAND);
node->setMaterialTexture( 0, driver->getTexture("../../media/sydney.bmp") );
}
Codice PHP:
smgr->addCameraSceneNode(0, vector3df(0,30,-40), vector3df(0,5,0));
EventReceiver_basic receiver(device);
device->setEventReceiver(&receiver);
return run ( device );
}
#if defined (_IRR_USE_WINDOWS_CE_DEVICE_)
#pragma comment(linker, "/subsystem:WINDOWSCE /ENTRY:main")
#elif defined (_IRR_WINDOWS_)
#pragma comment(linker, "/subsystem:windows /ENTRY:mainCRTStartup")
#endif
int main()
{
example_helloworld ();
example_customscenenode();
//example_terrain();
}
Versione scaricabile da QUI