• Benvenuto in Making Videogames!
  • Dai sfogo alla tua fantasia!
  • Crea il tuo Videogioco!
Benvenuto ospite! Login Registrati




Valutazione discussione:
  • 1 voto(i) - 5 media
  • 1
  • 2
  • 3
  • 4
  • 5
Tutorial 9 - Mesh Viewer
#1
Tutorial 9: Mesh Viewer

[Immagine: 009shot.jpg]

Questo tutorial mostra come creare un'applicazione molto più complessa con l'engine. Costruiremo un visualizzatore di mesh tramite le API e lo scene manager di Irrlicht. Nel tutorial mostreremo come creare Buttons, Windows, Toolbars, Menus, ComboBoxes, Tabcontrols, Editboxes, Images, MessageBoxes, SkyBoxes, come parserizzare e leggere un file XML con le funzioni integrate nell'engine per l'uso di file di XML.
Cominciamo come negli altri tutorials: includiamo tutti gli header necessari e indichiamo al Visual Studio come linkare la giusta libreria dell'engine, quindi dichiariamo alcune variabili globali. Aggiungiamo anche due namespace così da non dover utilizzare i nomi 'irr' e 'gui' in ogni classe dell'engine. Nel tutorial ovviamente useremo molti riferimenti al namespace 'gui'.
Codice PHP:
#include <irrlicht.h>
#include "driverChoice.h"

using namespace irr;
using namespace gui;

#ifdef _MSC_VER
#pragma comment(lib, "Irrlicht.lib")
#endif
Alcune variabili globali per un uso successivo.
IrrlichtDevice *Device 0;
core::stringc StartUpModelFile;
core::stringw MessageText;
core::stringw Caption;
scene::ISceneNodeModel 0;
scene::ISceneNodeSkyBox 0;
bool Octree=false;
bool UseLight=false;

scene::ICameraSceneNodeCamera[2] = {00};

// Values used to identify individual GUI elements
enum
{
    
GUI_ID_DIALOG_ROOT_WINDOW  0x10000,

    
GUI_ID_X_SCALE,
    
GUI_ID_Y_SCALE,
    
GUI_ID_Z_SCALE,

    
GUI_ID_OPEN_MODEL,
    
GUI_ID_SET_MODEL_ARCHIVE,
    
GUI_ID_LOAD_AS_OCTREE,

    
GUI_ID_SKY_BOX_VISIBLE,
    
GUI_ID_TOGGLE_DEBUG_INFO,

    
GUI_ID_DEBUG_OFF,
    
GUI_ID_DEBUG_BOUNDING_BOX,
    
GUI_ID_DEBUG_NORMALS,
    
GUI_ID_DEBUG_SKELETON,
    
GUI_ID_DEBUG_WIRE_OVERLAY,
    
GUI_ID_DEBUG_HALF_TRANSPARENT,
    
GUI_ID_DEBUG_BUFFERS_BOUNDING_BOXES,
    
GUI_ID_DEBUG_ALL,

    
GUI_ID_MODEL_MATERIAL_SOLID,
    
GUI_ID_MODEL_MATERIAL_TRANSPARENT,
    
GUI_ID_MODEL_MATERIAL_REFLECTION,

    
GUI_ID_CAMERA_MAYA,
    
GUI_ID_CAMERA_FIRST_PERSON,

    
GUI_ID_POSITION_TEXT,

    
GUI_ID_ABOUT,
    
GUI_ID_QUIT,

    
GUI_ID_TEXTUREFILTER,
    
GUI_ID_SKIN_TRANSPARENCY,
    
GUI_ID_SKIN_ANIMATION_FPS,

    
GUI_ID_BUTTON_SET_SCALE,
    
GUI_ID_BUTTON_SCALE_MUL10,
    
GUI_ID_BUTTON_SCALE_DIV10,
    
GUI_ID_BUTTON_OPEN_MODEL,
    
GUI_ID_BUTTON_SHOW_ABOUT,
    
GUI_ID_BUTTON_SHOW_TOOLBOX,
    
GUI_ID_BUTTON_SELECT_ARCHIVE,

    
GUI_ID_ANIMATION_INFO,

    
// And some magic numbers
    
MAX_FRAMERATE 80,
    
DEFAULT_FRAMERATE 30
}; 
Metodo per switchare sulla camera attivata.
Codice PHP:
void setActiveCamera(scene::ICameraSceneNodenewActive)
{
    if (
== Device)
        return;

    
scene::ICameraSceneNode active Device->getSceneManager()->getActiveCamera();
    
active->setInputReceiverEnabled(false);

    
newActive->setInputReceiverEnabled(true);
    
Device->getSceneManager()->setActiveCamera(newActive);

Metodo per settare la trasparenza della skin della gui agendo sul valore alpha di tutte le skin presenti.
Codice PHP:
void setSkinTransparency(s32 alphairr::gui::IGUISkin skin)
{
    for (
s32 i=0i<irr::gui::EGDC_COUNT ; ++i)
    {
        
video::SColor col skin->getColor((EGUI_DEFAULT_COLOR)i);
        
col.setAlpha(alpha);
        
skin->setColor((EGUI_DEFAULT_COLOR)icol);
    }

Aggiornamento del display per la scalatura dei modelli.
Codice PHP:
void updateScaleInfo(scene::ISceneNodemodel)
{
    
IGUIElementtoolboxWnd Device->getGUIEnvironment()->getRootGUIElement()->getElementFromId(GUI_ID_DIALOG_ROOT_WINDOWtrue);
    if (!
toolboxWnd)
        return;
    if (!
model)
    {
        
toolboxWnd->getElementFromId(GUI_ID_X_SCALEtrue)->setTextL"-" );
        
toolboxWnd->getElementFromId(GUI_ID_Y_SCALEtrue)->setTextL"-" );
        
toolboxWnd->getElementFromId(GUI_ID_Z_SCALEtrue)->setTextL"-" );
    }
    else
    {
        
core::vector3df scale model->getScale();
        
toolboxWnd->getElementFromId(GUI_ID_X_SCALEtrue)->setTextcore::stringw(scale.X).c_str() );
        
toolboxWnd->getElementFromId(GUI_ID_Y_SCALEtrue)->setTextcore::stringw(scale.Y).c_str() );
        
toolboxWnd->getElementFromId(GUI_ID_Z_SCALEtrue)->setTextcore::stringw(scale.Z).c_str() );
    }

Funzione showAboutText() che mostra una messagebox con un titolo ed un testo al suo interno. Il testo verrà memorizzato nelle variabili MessageText e Caption all'avvio del programma.
Codice PHP:
void showAboutText()
{
    
// create modal message box with the text
    // loaded from the xml file.
    
Device->getGUIEnvironment()->addMessageBox(
        
Caption.c_str(), MessageText.c_str());

La funzione loadModel() carica i modelli, poi li mostra utilizzando addAnimatedMeshSceneNode e lo scene manager. Niente di difficile. Viene mostrato anche un breve messaggio in una message box, nel caso non sia possibile caricare il modello.
Codice PHP:
void loadModel(const c8fn)
{
    
// modify the name if it a .pk3 file

    
io::path filename(fn);

    
io::path extension;
    
core::getFileNameExtension(extensionfilename);
    
extension.make_lower();

    
// if a texture is loaded apply it to the current model..
    
if (extension == ".jpg" || extension == ".pcx" ||
        
extension == ".png" || extension == ".ppm" ||
        
extension == ".pgm" || extension == ".pbm" ||
        
extension == ".psd" || extension == ".tga" ||
        
extension == ".bmp" || extension == ".wal" ||
        
extension == ".rgb" || extension == ".rgba")
    {
        
video::ITexture texture =
            
Device->getVideoDriver()->getTexturefilename );
        if ( 
texture && Model )
        {
            
// always reload texture
            
Device->getVideoDriver()->removeTexture(texture);
            
texture Device->getVideoDriver()->getTexturefilename );

            
Model->setMaterialTexture(0texture);
        }
        return;
    }
    
// if a archive is loaded add it to the FileArchive..
    
else if (extension == ".pk3" || extension == ".zip" || extension == ".pak" || extension == ".npk")
    {
        
Device->getFileSystem()->addFileArchive(filename.c_str());
        return;
    }

    
// load a model into the engine

    
if (Model)
        
Model->remove();

    
Model 0;

    if (
extension==".irr")
    {
        
core::array<scene::ISceneNode*> outNodes;
        
Device->getSceneManager()->loadScene(filename);
        
Device->getSceneManager()->getSceneNodesFromType(scene::ESNT_ANIMATED_MESHoutNodes);
        if (
outNodes.size())
            
Model outNodes[0];
        return;
    }

    
scene::IAnimatedMeshDevice->getSceneManager()->getMeshfilename.c_str() );

    if (!
m)
    {
        
// model could not be loaded

        
if (StartUpModelFile != filename)
            
Device->getGUIEnvironment()->addMessageBox(
            
Caption.c_str(), L"The model could not be loaded. " \
            
L"Maybe it is not a supported file format.");
        return;
    }

    
// set default material properties

    
if (Octree)
        
Model Device->getSceneManager()->addOctreeSceneNode(m->getMesh(0));
    else
    {
        
scene::IAnimatedMeshSceneNodeanimModel Device->getSceneManager()->addAnimatedMeshSceneNode(m);
        
animModel->setAnimationSpeed(30);
        
Model animModel;
    }
    
Model->setMaterialFlag(video::EMF_LIGHTINGUseLight);
    
Model->setMaterialFlag(video::EMF_NORMALIZE_NORMALSUseLight);
//  Model->setMaterialFlag(video::EMF_BACK_FACE_CULLING, false);
    
Model->setDebugDataVisible(scene::EDS_OFF);

    
// we need to uncheck the menu entries. would be cool to fake a menu event, but
    // that's not so simple. so we do it brute force
    
gui::IGUIContextMenumenu = (gui::IGUIContextMenu*)Device->getGUIEnvironment()->getRootGUIElement()->getElementFromId(GUI_ID_TOGGLE_DEBUG_INFOtrue);
    if (
menu)
        for(
int item 1item 6; ++item)
            
menu->setItemChecked(itemfalse);
    
updateScaleInfo(Model);

La funzione createToolBox() crea una finestra con una toolbox. In questo esempio per ora la toolbox conterrà solo una tab con dentro tre caselle di testo editabili dove scrivere i valori per scalare il modello.
Codice PHP:
void createToolBox()
{
    
// remove tool box if already there
    
IGUIEnvironmentenv Device->getGUIEnvironment();
    
IGUIElementroot env->getRootGUIElement();
    
IGUIElementroot->getElementFromId(GUI_ID_DIALOG_ROOT_WINDOWtrue);
    if (
e)
        
e->remove();

    
// create the toolbox window
    
IGUIWindowwnd env->addWindow(core::rect<s32>(600,45,800,480),
        
falseL"Toolset"0GUI_ID_DIALOG_ROOT_WINDOW);

    
// create tab control and tabs
    
IGUITabControltab env->addTabControl(
        
core::rect<s32>(2,20,800-602,480-7), wndtruetrue);

    
IGUITabt1 tab->addTab(L"Config");

    
// add some edit boxes and a button to tab one
    
env->addStaticText(L"Scale:",
            
core::rect<s32>(10,20,60,45), falsefalset1);
    
env->addStaticText(L"X:"core::rect<s32>(22,48,40,66), falsefalset1);
    
env->addEditBox(L"1.0"core::rect<s32>(40,46,130,66), truet1GUI_ID_X_SCALE);
    
env->addStaticText(L"Y:"core::rect<s32>(22,82,40,96), falsefalset1);
    
env->addEditBox(L"1.0"core::rect<s32>(40,76,130,96), truet1GUI_ID_Y_SCALE);
    
env->addStaticText(L"Z:"core::rect<s32>(22,108,40,126), falsefalset1);
    
env->addEditBox(L"1.0"core::rect<s32>(40,106,130,126), truet1GUI_ID_Z_SCALE);

    
env->addButton(core::rect<s32>(10,134,85,165), t1GUI_ID_BUTTON_SET_SCALEL"Set");

    
// quick scale buttons
    
env->addButton(core::rect<s32>(65,20,95,40), t1GUI_ID_BUTTON_SCALE_MUL10L"* 10");
    
env->addButton(core::rect<s32>(100,20,130,40), t1GUI_ID_BUTTON_SCALE_DIV10L"* 0.1");

    
updateScaleInfo(Model);

    
// add transparency control
    
env->addStaticText(L"GUI Transparency Control:",
            
core::rect<s32>(10,200,150,225), truefalset1);
    
IGUIScrollBarscrollbar env->addScrollBar(true,
            
core::rect<s32>(10,225,150,240), t1GUI_ID_SKIN_TRANSPARENCY);
    
scrollbar->setMax(255);
    
scrollbar->setPos(255);

    
// add framerate control
    
env->addStaticText(L":"core::rect<s32>(10,240,150,265), truefalset1);
    
env->addStaticText(L"Framerate:",
            
core::rect<s32>(12,240,75,265), falsefalset1);
    
// current frame info
    
env->addStaticText(L""core::rect<s32>(75,240,200,265), falsefalset1,
            
GUI_ID_ANIMATION_INFO);
    
scrollbar env->addScrollBar(true,
            
core::rect<s32>(10,265,150,280), t1GUI_ID_SKIN_ANIMATION_FPS);
    
scrollbar->setMax(MAX_FRAMERATE);
    
scrollbar->setMin(-MAX_FRAMERATE);
    
scrollbar->setPos(DEFAULT_FRAMERATE);
    
scrollbar->setSmallStep(1);

La funzione updateToolBox() è chiamata ad ogni frame per aggiornare dinamicamente le informazioni inserite nella toolbox.
Codice PHP:
void updateToolBox()
{
    
IGUIEnvironmentenv Device->getGUIEnvironment();
    
IGUIElementroot env->getRootGUIElement();
    
IGUIElementdlg root->getElementFromId(GUI_ID_DIALOG_ROOT_WINDOWtrue);
    if (!
dlg )
        return;

    
// update the info we have about the animation of the model
    
IGUIStaticText *  aniInfo = (IGUIStaticText *)(dlg->getElementFromId(GUI_ID_ANIMATION_INFOtrue));
    if (
aniInfo)
    {
        if ( 
Model && scene::ESNT_ANIMATED_MESH == Model->getType() )
        {
            
scene::IAnimatedMeshSceneNodeanimatedModel = (scene::IAnimatedMeshSceneNode*)Model;

            
core::stringw str( (s32)core::round_(animatedModel->getAnimationSpeed()) );
            
str += L" Frame: ";
            
str += core::stringw((s32)animatedModel->getFrameNr());
            
aniInfo->setText(str.c_str());
        }
        else
            
aniInfo->setText(L"");
    }
}

void onKillFocus()
{
    
// Avoid that the FPS-camera continues moving when the user presses alt-tab while 
    // moving the camera. 
    
const core::list<scene::ISceneNodeAnimator*>& animators Camera[1]->getAnimators();
    
core::list<irr::scene::ISceneNodeAnimator*>::ConstIterator iter animators.begin();
    while ( 
iter != animators.end() )
    {
        if ( (*
iter)->getType() == scene::ESNAT_CAMERA_FPS )
        {
            
// we send a key-down event for all keys used by this animator
            
scene::ISceneNodeAnimatorCameraFPS fpsAnimator static_cast<scene::ISceneNodeAnimatorCameraFPS*>(*iter);
            const 
core::array<SKeyMap>& keyMap fpsAnimator->getKeyMap();
            for ( 
irr::u32 i=0ikeyMap.size(); ++)
            {
                
irr::SEvent event;
                
event.EventType EET_KEY_INPUT_EVENT;
                
event.KeyInput.Key keyMap[i].KeyCode;
                
event.KeyInput.PressedDown false;
                
fpsAnimator->OnEvent(event);
            }
        }
        ++
iter;
    }

La funzione hasModalDialog() verifica la presenza di una finestra modale aperta (le finestre modali sono finestre di dialogo che non sono sovrapponibili che necessitano quindi di essere chiuse per essere superate)
Codice PHP:
bool hasModalDialog()
{
    if ( !
Device )
        return 
false;
    
IGUIEnvironmentenv Device->getGUIEnvironment();
    
IGUIElement focused env->getFocus();
    while ( 
focused )
    {
        if ( 
focused->isVisible() && focused->hasType(EGUIET_MODAL_SCREEN) )
            return 
true;
        
focused focused->getParent();
    }
    return 
false;

Per catturare tutti gli eventi che nascono dagli elementi della GUI ci serve creare un ricevitore di eventi. Questo è molto semplice. Quando arriva un evento viene trovato l'id dell'elemento che lo ha sollevato e il tipo di evento catturato, quindi si esegue l'azione che vi corrisponde. Per esempio, se la voce di menù con id GUI_ID_OPEN_MODEL viene selezionata, andiamo ad aprire la finestra di dialogo “Apri file..”.
Codice PHP:
class MyEventReceiver : public IEventReceiver
{
public:
    
virtual bool OnEvent(const SEventevent)
    {
        
// Escape swaps Camera Input
        
if (event.EventType == EET_KEY_INPUT_EVENT &&
            
event.KeyInput.PressedDown == false)
        {
            if ( 
OnKeyUp(event.KeyInput.Key) )
                return 
true;
        }

        if (
event.EventType == EET_GUI_EVENT)
        {
            
s32 id event.GUIEvent.Caller->getID();
            
IGUIEnvironmentenv Device->getGUIEnvironment();

            switch(
event.GUIEvent.EventType)
            {
            case 
EGET_MENU_ITEM_SELECTED:
                    
// a menu item was clicked
                    
OnMenuItemSelected( (IGUIContextMenu*)event.GUIEvent.Caller );
                break;

            case 
EGET_FILE_SELECTED:
                {
                    
// load the model file, selected in the file open dialog
                    
IGUIFileOpenDialogdialog =
                        (
IGUIFileOpenDialog*)event.GUIEvent.Caller;
                    
loadModel(core::stringc(dialog->getFileName()).c_str());
                }
                break;

            case 
EGET_SCROLL_BAR_CHANGED:

                
// control skin transparency
                
if (id == GUI_ID_SKIN_TRANSPARENCY)
                {
                    const 
s32 pos = ((IGUIScrollBar*)event.GUIEvent.Caller)->getPos();
                    
setSkinTransparency(posenv->getSkin());
                }
                
// control animation speed
                
else if (id == GUI_ID_SKIN_ANIMATION_FPS)
                {
                    const 
s32 pos = ((IGUIScrollBar*)event.GUIEvent.Caller)->getPos();
                    if (
scene::ESNT_ANIMATED_MESH == Model->getType())
                        ((
scene::IAnimatedMeshSceneNode*)Model)->setAnimationSpeed((f32)pos);
                }
                break;

            case 
EGET_COMBO_BOX_CHANGED:

                
// control anti-aliasing/filtering
                
if (id == GUI_ID_TEXTUREFILTER)
                {
                    
OnTextureFilterSelected( (IGUIComboBox*)event.GUIEvent.Caller );
                }
                break;

            case 
EGET_BUTTON_CLICKED:

                switch(
id)
                {
                case 
GUI_ID_BUTTON_SET_SCALE:
                    {
                        
// set scale
                        
gui::IGUIElementroot env->getRootGUIElement();
                        
core::vector3df scale;
                        
core::stringc s;

                        
root->getElementFromId(GUI_ID_X_SCALEtrue)->getText();
                        
scale.= (f32)atof(s.c_str());
                        
root->getElementFromId(GUI_ID_Y_SCALEtrue)->getText();
                        
scale.= (f32)atof(s.c_str());
                        
root->getElementFromId(GUI_ID_Z_SCALEtrue)->getText();
                        
scale.= (f32)atof(s.c_str());

                        if (
Model)
                            
Model->setScale(scale);
                        
updateScaleInfo(Model);
                    }
                    break;
                case 
GUI_ID_BUTTON_SCALE_MUL10:
                    if (
Model)
                        
Model->setScale(Model->getScale()*10.f);
                    
updateScaleInfo(Model);
                    break;
                case 
GUI_ID_BUTTON_SCALE_DIV10:
                    if (
Model)
                        
Model->setScale(Model->getScale()*0.1f);
                    
updateScaleInfo(Model);
                    break;
                case 
GUI_ID_BUTTON_OPEN_MODEL:
                    
env->addFileOpenDialog(L"Please select a model file to open");
                    break;
                case 
GUI_ID_BUTTON_SHOW_ABOUT:
                    
showAboutText();
                    break;
                case 
GUI_ID_BUTTON_SHOW_TOOLBOX:
                    
createToolBox();
                    break;
                case 
GUI_ID_BUTTON_SELECT_ARCHIVE:
                    
env->addFileOpenDialog(L"Please select your game archive/directory");
                    break;
                }

                break;
            default:
                break;
            }
        }

        return 
false;
    } 
Gestiamo gli eventi per la tastiera.
Codice PHP:
bool OnKeyUp(irr::EKEY_CODE keyCode)
    {
        
// Don't handle keys if we have a modal dialog open as it would lead 
        // to unexpected application behaviour for the user.
        
if ( hasModalDialog() )
            return 
false;
        
        if (
keyCode == irr::KEY_ESCAPE)
        {
            if (
Device)
            {
                
scene::ICameraSceneNode camera =
                    
Device->getSceneManager()->getActiveCamera();
                if (
camera)
                {
                    
camera->setInputReceiverEnabled( !camera->isInputReceiverEnabled() );
                }
                return 
true;
            }
        }
        else if (
keyCode == irr::KEY_F1)
        {
            if (
Device)
            {
                
IGUIElementelem Device->getGUIEnvironment()->getRootGUIElement()->getElementFromId(GUI_ID_POSITION_TEXT);
                if (
elem)
                    
elem->setVisible(!elem->isVisible());
            }
        }
        else if (
keyCode == irr::KEY_KEY_M)
        {
            if (
Device)
                
Device->minimizeWindow();
        }
        else if (
keyCode == irr::KEY_KEY_L)
        {
            
UseLight=!UseLight;
            if (
Model)
            {
                
Model->setMaterialFlag(video::EMF_LIGHTINGUseLight);
                
Model->setMaterialFlag(video::EMF_NORMALIZE_NORMALSUseLight);
            }
        }
        return 
false;
    } 
Gestiamo gli eventi che arrivano dai click sul menù.
Codice PHP:
void OnMenuItemSelectedIGUIContextMenumenu )
    {
        
s32 id menu->getItemCommandId(menu->getSelectedItem());
        
IGUIEnvironmentenv Device->getGUIEnvironment();

        switch(
id)
        {
        case 
GUI_ID_OPEN_MODEL// FilOnButtonSetScalinge -> Open Model
            
env->addFileOpenDialog(L"Please select a model file to open");
            break;
        case 
GUI_ID_SET_MODEL_ARCHIVE// File -> Set Model Archive
            
env->addFileOpenDialog(L"Please select your game archive/directory");
            break;
        case 
GUI_ID_LOAD_AS_OCTREE// File -> LoadAsOctree
            
Octree = !Octree;
            
menu->setItemChecked(menu->getSelectedItem(), Octree);
            break;
        case 
GUI_ID_QUIT// File -> Quit
            
Device->closeDevice();
            break;
        case 
GUI_ID_SKY_BOX_VISIBLE// View -> Skybox
            
menu->setItemChecked(menu->getSelectedItem(), !menu->isItemChecked(menu->getSelectedItem()));
            
SkyBox->setVisible(!SkyBox->isVisible());
            break;
        case 
GUI_ID_DEBUG_OFF// View -> Debug Information
            
menu->setItemChecked(menu->getSelectedItem()+1false);
            
menu->setItemChecked(menu->getSelectedItem()+2false);
            
menu->setItemChecked(menu->getSelectedItem()+3false);
            
menu->setItemChecked(menu->getSelectedItem()+4false);
            
menu->setItemChecked(menu->getSelectedItem()+5false);
            
menu->setItemChecked(menu->getSelectedItem()+6false);
            if (
Model)
                
Model->setDebugDataVisible(scene::EDS_OFF);
            break;
        case 
GUI_ID_DEBUG_BOUNDING_BOX// View -> Debug Information
            
menu->setItemChecked(menu->getSelectedItem(), !menu->isItemChecked(menu->getSelectedItem()));
            if (
Model)
                
Model->setDebugDataVisible((scene::E_DEBUG_SCENE_TYPE)(Model->isDebugDataVisible()^scene::EDS_BBOX));
            break;
        case 
GUI_ID_DEBUG_NORMALS// View -> Debug Information
            
menu->setItemChecked(menu->getSelectedItem(), !menu->isItemChecked(menu->getSelectedItem()));
            if (
Model)
                
Model->setDebugDataVisible((scene::E_DEBUG_SCENE_TYPE)(Model->isDebugDataVisible()^scene::EDS_NORMALS));
            break;
        case 
GUI_ID_DEBUG_SKELETON// View -> Debug Information
            
menu->setItemChecked(menu->getSelectedItem(), !menu->isItemChecked(menu->getSelectedItem()));
            if (
Model)
                
Model->setDebugDataVisible((scene::E_DEBUG_SCENE_TYPE)(Model->isDebugDataVisible()^scene::EDS_SKELETON));
            break;
        case 
GUI_ID_DEBUG_WIRE_OVERLAY// View -> Debug Information
            
menu->setItemChecked(menu->getSelectedItem(), !menu->isItemChecked(menu->getSelectedItem()));
            if (
Model)
                
Model->setDebugDataVisible((scene::E_DEBUG_SCENE_TYPE)(Model->isDebugDataVisible()^scene::EDS_MESH_WIRE_OVERLAY));
            break;
        case 
GUI_ID_DEBUG_HALF_TRANSPARENT// View -> Debug Information
            
menu->setItemChecked(menu->getSelectedItem(), !menu->isItemChecked(menu->getSelectedItem()));
            if (
Model)
                
Model->setDebugDataVisible((scene::E_DEBUG_SCENE_TYPE)(Model->isDebugDataVisible()^scene::EDS_HALF_TRANSPARENCY));
            break;
        case 
GUI_ID_DEBUG_BUFFERS_BOUNDING_BOXES// View -> Debug Information
            
menu->setItemChecked(menu->getSelectedItem(), !menu->isItemChecked(menu->getSelectedItem()));
            if (
Model)
                
Model->setDebugDataVisible((scene::E_DEBUG_SCENE_TYPE)(Model->isDebugDataVisible()^scene::EDS_BBOX_BUFFERS));
            break;
        case 
GUI_ID_DEBUG_ALL// View -> Debug Information
            
menu->setItemChecked(menu->getSelectedItem()-1true);
            
menu->setItemChecked(menu->getSelectedItem()-2true);
            
menu->setItemChecked(menu->getSelectedItem()-3true);
            
menu->setItemChecked(menu->getSelectedItem()-4true);
            
menu->setItemChecked(menu->getSelectedItem()-5true);
            
menu->setItemChecked(menu->getSelectedItem()-6true);
            if (
Model)
                
Model->setDebugDataVisible(scene::EDS_FULL);
            break;
        case 
GUI_ID_ABOUT// Help->About
            
showAboutText();
            break;
        case 
GUI_ID_MODEL_MATERIAL_SOLID// View -> Material -> Solid
            
if (Model)
                
Model->setMaterialType(video::EMT_SOLID);
            break;
        case 
GUI_ID_MODEL_MATERIAL_TRANSPARENT// View -> Material -> Transparent
            
if (Model)
                
Model->setMaterialType(video::EMT_TRANSPARENT_ADD_COLOR);
            break;
        case 
GUI_ID_MODEL_MATERIAL_REFLECTION// View -> Material -> Reflection
            
if (Model)
                
Model->setMaterialType(video::EMT_SPHERE_MAP);
            break;

        case 
GUI_ID_CAMERA_MAYA:
            
setActiveCamera(Camera[0]);
            break;
        case 
GUI_ID_CAMERA_FIRST_PERSON:
            
setActiveCamera(Camera[1]);
            break;
        }
    } 
Gestiamo gli eventi per la combobox che comanda i filtri sulle texture.
Codice PHP:
void OnTextureFilterSelectedIGUIComboBoxcombo )
    {
        
s32 pos combo->getSelected();
        switch (
pos)
        {
            case 
0:
            if (
Model)
            {
                
Model->setMaterialFlag(video::EMF_BILINEAR_FILTERfalse);
                
Model->setMaterialFlag(video::EMF_TRILINEAR_FILTERfalse);
                
Model->setMaterialFlag(video::EMF_ANISOTROPIC_FILTERfalse);
            }
            break;
            case 
1:
            if (
Model)
            {
                
Model->setMaterialFlag(video::EMF_BILINEAR_FILTERtrue);
                
Model->setMaterialFlag(video::EMF_TRILINEAR_FILTERfalse);
            }
            break;
            case 
2:
            if (
Model)
            {
                
Model->setMaterialFlag(video::EMF_BILINEAR_FILTERfalse);
                
Model->setMaterialFlag(video::EMF_TRILINEAR_FILTERtrue);
            }
            break;
            case 
3:
            if (
Model)
            {
                
Model->setMaterialFlag(video::EMF_ANISOTROPIC_FILTERtrue);
            }
            break;
            case 
4:
            if (
Model)
            {
                
Model->setMaterialFlag(video::EMF_ANISOTROPIC_FILTERfalse);
            }
            break;
        }
    }
}; 
Il più è fatto. Ci serve solo creare il solito device del Irrlicht Engine poi i buttons i menu e la toolbar. Avviamo l'engine come sempre usando createDevice(). Per permettere che l'applicazione possa catturare gli eventi, rendiamo il nostro ricevitore di eventi uno dei parametri dentro la chiamata al createdevice() stessa. Come si vede, al device di Irrlicht impostiamo una proprietà a 'true' la IrrlichtDevice:ConfusedetResizeable(). Così avremo una finestra ridimensionabile, molto utile per un visualizzatore di mesh.
Codice PHP:
int main(int argccharargv[])
{
    
// ask user for driver
    
video::E_DRIVER_TYPE driverType=driverChoiceConsole();
    if (
driverType==video::EDT_COUNT)
        return 
1;

    
// create device and exit if creation failed
    
MyEventReceiver receiver;
    
Device createDevice(driverTypecore::dimension2d<u32>(800600),
        
16falsefalsefalse, &receiver);

    if (
Device == 0)
        return 
1// could not create selected driver.

    
Device->setResizable(true);

    
Device->setWindowCaption(L"Irrlicht Engine - Loading...");

    
video::IVideoDriverdriver Device->getVideoDriver();
    
IGUIEnvironmentenv Device->getGUIEnvironment();
    
scene::ISceneManagersmgr Device->getSceneManager();
    
smgr->getParameters()->setAttribute(scene::COLLADA_CREATE_SCENE_INSTANCEStrue);

    
driver->setTextureCreationFlag(video::ETCF_ALWAYS_32_BITtrue);

    
smgr->addLightSceneNode(0core::vector3df(200,200,200),
        
video::SColorf(1.0f,1.0f,1.0f),2000);
    
smgr->setAmbientLight(video::SColorf(0.3f,0.3f,0.3f));
    
// add our media directory as "search path"
    
Device->getFileSystem()->addFileArchive("../../media/"); 
Il passo successivo è leggere il file di configurazione. Questo è registrato su un file in formato xml e grosso modo assomiglia a questo:
Codice PHP:
<?xml version="1.0"?>
        <config>
                <startUpModel file="some filename" />
                <messageText caption="Irrlicht Engine Mesh Viewer">
                        Hello!
                </messageText>
        </config> 
Ci servono i dati che conserva per scriverli nelle variabili globali StartUpModelFile, MessageText e Caption. Lo facciamo usando il parser di XML integrato nel Irrlicht Engine:
Codice PHP:
// read configuration from xml file

    
io::IXMLReaderxml Device->getFileSystem()->createXMLReaderL"config.xml");

    while(
xml && xml->read())
    {
        switch(
xml->getNodeType())
        {
        case 
io::EXN_TEXT:
            
// in this xml file, the only text which occurs is the
            // messageText
            
MessageText xml->getNodeData();
            break;
        case 
io::EXN_ELEMENT:
            {
                if (
core::stringw("startUpModel") == xml->getNodeName())
                    
StartUpModelFile xml->getAttributeValue(L"file");
                else
                if (
core::stringw("messageText") == xml->getNodeName())
                    
Caption xml->getAttributeValue(L"caption");
            }
            break;
        default:
            break;
        }
    }

    if (
xml)
        
xml->drop(); // don't forget to delete the xml reader

    
if (argc 1)
        
StartUpModelFile argv[1]; 
Non è stato difficile. Ora impostiamo un font carino e creiamo il menù. Si possono creare anche sottomenù da ciascun elemento del menù. La chiamata menu->addItem(L"File", -1, true, true); per esempio, aggiunge una nuova voce di menù "File" e il suo id -1. I parametri che seguono indicano che la voce del menù deve essere attiva e quello dopo indica che potrebbe esserci un sottomenù che parte da quella voce. Il submenu può essere raggiunto tramite menu->getSubMenu(0), perché la voce "File" è indicata dall'indice 0 essendo stata la prima ad essere creata.
Codice PHP:
// set a nicer font

    
IGUISkinskin env->getSkin();
    
IGUIFontfont env->getFont("fonthaettenschweiler.bmp");
    if (
font)
        
skin->setFont(font);

    
// create menu
    
gui::IGUIContextMenumenu env->addMenu();
    
menu->addItem(L"File", -1truetrue);
    
menu->addItem(L"View", -1truetrue);
    
menu->addItem(L"Camera", -1truetrue);
    
menu->addItem(L"Help", -1truetrue);

    
gui::IGUIContextMenusubmenu;
    
submenu menu->getSubMenu(0);
    
submenu->addItem(L"Open Model File & Texture..."GUI_ID_OPEN_MODEL);
    
submenu->addItem(L"Set Model Archive..."GUI_ID_SET_MODEL_ARCHIVE);
    
submenu->addItem(L"Load as Octree"GUI_ID_LOAD_AS_OCTREE);
    
submenu->addSeparator();
    
submenu->addItem(L"Quit"GUI_ID_QUIT);

    
submenu menu->getSubMenu(1);
    
submenu->addItem(L"sky box visible"GUI_ID_SKY_BOX_VISIBLEtruefalsetrue);
    
submenu->addItem(L"toggle model debug information"GUI_ID_TOGGLE_DEBUG_INFOtruetrue);
    
submenu->addItem(L"model material", -1truetrue );

    
submenu submenu->getSubMenu(1);
    
submenu->addItem(L"Off"GUI_ID_DEBUG_OFF);
    
submenu->addItem(L"Bounding Box"GUI_ID_DEBUG_BOUNDING_BOX);
    
submenu->addItem(L"Normals"GUI_ID_DEBUG_NORMALS);
    
submenu->addItem(L"Skeleton"GUI_ID_DEBUG_SKELETON);
    
submenu->addItem(L"Wire overlay"GUI_ID_DEBUG_WIRE_OVERLAY);
    
submenu->addItem(L"Half-Transparent"GUI_ID_DEBUG_HALF_TRANSPARENT);
    
submenu->addItem(L"Buffers bounding boxes"GUI_ID_DEBUG_BUFFERS_BOUNDING_BOXES);
    
submenu->addItem(L"All"GUI_ID_DEBUG_ALL);

    
submenu menu->getSubMenu(1)->getSubMenu(2);
    
submenu->addItem(L"Solid"GUI_ID_MODEL_MATERIAL_SOLID);
    
submenu->addItem(L"Transparent"GUI_ID_MODEL_MATERIAL_TRANSPARENT);
    
submenu->addItem(L"Reflection"GUI_ID_MODEL_MATERIAL_REFLECTION);

    
submenu menu->getSubMenu(2);
    
submenu->addItem(L"Maya Style"GUI_ID_CAMERA_MAYA);
    
submenu->addItem(L"First Person"GUI_ID_CAMERA_FIRST_PERSON);

    
submenu menu->getSubMenu(3);
    
submenu->addItem(L"About"GUI_ID_ABOUT); 
Sotto al menu vogliamo una toolbar, dentro cui andremo a paizzare alcuni pulsanti colorati e una importantissima cosa come un combobox, per ora senza senso.
Codice PHP:
// create toolbar

    
gui::IGUIToolBarbar env->addToolBar();

    
video::ITextureimage driver->getTexture("open.png");
    
bar->addButton(GUI_ID_BUTTON_OPEN_MODEL0L"Open a model",image0falsetrue);

    
image driver->getTexture("tools.png");
    
bar->addButton(GUI_ID_BUTTON_SHOW_TOOLBOX0L"Open Toolset",image0falsetrue);

    
image driver->getTexture("zip.png");
    
bar->addButton(GUI_ID_BUTTON_SELECT_ARCHIVE0L"Set Model Archive",image0falsetrue);

    
image driver->getTexture("help.png");
    
bar->addButton(GUI_ID_BUTTON_SHOW_ABOUT0L"Open Help"image0falsetrue);

    
// create a combobox for texture filters

    
gui::IGUIComboBoxbox env->addComboBox(core::rect<s32>(250,4,350,23), barGUI_ID_TEXTUREFILTER);
    
box->addItem(L"No filtering");
    
box->addItem(L"Bilinear");
    
box->addItem(L"Trilinear");
    
box->addItem(L"Anisotropic");
    
box->addItem(L"Isotropic"); 
Per rendere l'editor più bello da vedere disabilitiamo la trasparenza degli elementi della GUI e aggiungiamo un logo di Irrlicht Engine. In aggiunta mostriamo un testo che indica gli fps e cambiamo il titolo della finestra.
Codice PHP:
// disable alpha

    
for (s32 i=0i<gui::EGDC_COUNT ; ++i)
    {
        
video::SColor col env->getSkin()->getColor((gui::EGUI_DEFAULT_COLOR)i);
        
col.setAlpha(255);
        
env->getSkin()->setColor((gui::EGUI_DEFAULT_COLOR)icol);
    }

    
// add a tabcontrol

    
createToolBox();

    
// create fps text

    
IGUIStaticTextfpstext env->addStaticText(L"",
            
core::rect<s32>(400,4,570,23), truefalsebar);

    
IGUIStaticTextpostext env->addStaticText(L"",
            
core::rect<s32>(10,50,470,80),falsefalse0GUI_ID_POSITION_TEXT);
    
postext->setVisible(false);

    
// set window caption

    
Caption += " - [";
    
Caption += driver->getName();
    
Caption += "]";
    
Device->setWindowCaption(Caption.c_str()); 
L'applicazione è quasi completa. Andiamo a mostrare la finestra 'about' all'avvio dell'applicazione e carichiamo il modello. Sempre per rendere il tutto più piacevole creiamo una skybox e aggiungiamo una camera controllata dall'utente per dare più interattività. Finalmente, tutto viene disegnato nel solito loop standard del rendering.
Codice PHP:
// show about message box and load default model
    
if (argc==1)
        
showAboutText();
    
loadModel(StartUpModelFile.c_str());

    
// add skybox

    
SkyBox smgr->addSkyBoxSceneNode(
        
driver->getTexture("irrlicht2_up.jpg"),
        
driver->getTexture("irrlicht2_dn.jpg"),
        
driver->getTexture("irrlicht2_lf.jpg"),
        
driver->getTexture("irrlicht2_rt.jpg"),
        
driver->getTexture("irrlicht2_ft.jpg"),
        
driver->getTexture("irrlicht2_bk.jpg"));

    
// add a camera scene node
    
Camera[0] = smgr->addCameraSceneNodeMaya();
    
Camera[0]->setFarValue(20000.f);
    
// Maya cameras reposition themselves relative to their target, so target the location
    // where the mesh scene node is placed.
    
Camera[0]->setTarget(core::vector3df(0,30,0));

    
Camera[1] = smgr->addCameraSceneNodeFPS();
    
Camera[1]->setFarValue(20000.f);
    
Camera[1]->setPosition(core::vector3df(0,0,-70));
    
Camera[1]->setTarget(core::vector3df(0,30,0));

    
setActiveCamera(Camera[0]);

    
// load the irrlicht engine logo
    
IGUIImage *img =
        
env->addImage(driver->getTexture("irrlichtlogo2.png"),
            
core::position2d<s32>(10driver->getScreenSize().Height 128));

    
// lock the logo's edges to the bottom left corner of the screen
    
img->setAlignment(EGUIA_UPPERLEFTEGUIA_UPPERLEFT,
            
EGUIA_LOWERRIGHTEGUIA_LOWERRIGHT);

    
// remember state so we notice when the window does lose the focus
    
bool hasFocus Device->isWindowFocused();

    
// draw everything

    
while(Device->run() && driver)
    {
        
// Catch focus changes (workaround until Irrlicht has events for this)
        
bool focused Device->isWindowFocused();
        if ( 
hasFocus && !focused )
            
onKillFocus();
        
hasFocus focused;

        if (
Device->isWindowActive())
        {
            
driver->beginScene(truetruevideo::SColor(150,50,50,50));

            
smgr->drawAll();
            
env->drawAll();

            
driver->endScene();

            
// update information about current frame-rate
            
core::stringw str(L"FPS: ");
            
str.append(core::stringw(driver->getFPS()));
            
str += L" Tris: ";
            
str.append(core::stringw(driver->getPrimitiveCountDrawn()));
            
fpstext->setText(str.c_str());

            
// update information about the active camera
            
scene::ICameraSceneNodecam Device->getSceneManager()->getActiveCamera();
            
str L"Pos: ";
            
str.append(core::stringw(cam->getPosition().X));
            
str += L" ";
            
str.append(core::stringw(cam->getPosition().Y));
            
str += L" ";
            
str.append(core::stringw(cam->getPosition().Z));
            
str += L" Tgt: ";
            
str.append(core::stringw(cam->getTarget().X));
            
str += L" ";
            
str.append(core::stringw(cam->getTarget().Y));
            
str += L" ";
            
str.append(core::stringw(cam->getTarget().Z));
            
postext->setText(str.c_str());

            
// update the tool dialog
            
updateToolBox();
        }
        else
            
Device->yield();
    }

    
Device->drop();
    return 
0;


Versione pdf scaricabile da QUI
 
Rispondi
  


Discussioni simili
Discussione Autore Risposte Letto Ultimo messaggio
  Tutorial 22 - Material Viewer Chip 0 479 24-08-2015, 11:16 AM
Ultimo messaggio: Chip
  Mappe e mesh Nos9110 2 1,380 29-08-2010, 02:16 AM
Ultimo messaggio: Nos9110

Vai al forum:


Browsing: 1 Ospite(i)