Tutoriel Irrlicht 21

Explorateur Quake 3

Ce tutoriel est une traduction de l'anglais des tutoriels officiels d'Irrlicht.

Il montre comment charger différentes cartes Quake 3.

Commentez Donner une note  l'article (5)

Article lu   fois.

Les deux auteur et traducteur

Site personnel

Traducteur : Site personnel

Liens sociaux

Viadeo Twitter Facebook Share on Google+   

I. Configuration

Image non disponible

Fonctionnalités :

  • charge une archive BSP pendant l'exécution à partir du menu ;
  • charge une carte à partir du menu et affiche un aperçu ;
  • met le pilote vidéo pendant l'exécution suivant le choix dans le menu ;
  • ajuste le niveau Gamma à l'exécution ;
  • crée des SceneNodes pour les ombres ;
  • charge EntryList et crée les SceneNodes entité ;
  • crée les joueurs avec des armes et gestion des collisions ;
  • joue de la musique.

Vous pouvez télécharger la démonstration de Quake III Arena (copyright id software) à partir du lien suivant : ftp://ftp.idsoftware.com/idstuff/quake3/win32/q3ademo.exe

Copyright 2006-2011 Burningwater, Thomas Alten.

 
Sélectionnez
#include "driverChoice.h"
#include <irrlicht.h>
#include "q3factory.h"
#include "sound.h"

GameData est utilisé pour regrouper les données nécessaires à l'exécution du jeu.

 
Sélectionnez
struct GameData
{
    GameData ( const path &startupDir) :
        retVal(0), StartupDir(startupDir), createExDevice(0), Device(0)
    {
        setDefault ();
    }

    void setDefault ();
    s32 save ( const path &filename );
    s32 load ( const path &filename );

    s32 debugState;
    s32 gravityState;
    s32 flyTroughState;
    s32 wireFrame;
    s32 guiActive;
    s32 guiInputActive;
    f32 GammaValue;
    s32 retVal;
    s32 sound;

    path StartupDir;
    stringw CurrentMapName;
    array<path> CurrentArchiveList;

    vector3df PlayerPosition;
    vector3df PlayerRotation;

    tQ3EntityList Variable;

    Q3LevelLoadParameter loadParam;
    SIrrlichtCreationParameters deviceParam;
    funcptr_createDeviceEx createExDevice;
    IrrlichtDevice *Device;
};

Définit la configuration par défaut.

 
Sélectionnez
void GameData::setDefault ()
{
    debugState = EDS_OFF;
    gravityState = 1;
    flyTroughState = 0;
    wireFrame = 0;
    guiActive = 1;
    guiInputActive = 0;
    GammaValue = 1.f;

    // deviceParam par défaut;
#if defined ( _IRR_WINDOWS_ )
    deviceParam.DriverType = EDT_DIRECT3D9;
#else
    deviceParam.DriverType = EDT_OPENGL;
#endif
    deviceParam.WindowSize.Width = 800;
    deviceParam.WindowSize.Height = 600;
    deviceParam.Fullscreen = false;
    deviceParam.Bits = 24;
    deviceParam.ZBufferBits = 16;
    deviceParam.Vsync = false;
    deviceParam.AntiAlias = false;

    // loadParam par défaut de Quake 3
    loadParam.defaultLightMapMaterial = EMT_LIGHTMAP;
    loadParam.defaultModulate = EMFN_MODULATE_1X;
    loadParam.defaultFilter = EMF_ANISOTROPIC_FILTER;
    loadParam.verbose = 2;
    loadParam.mergeShaderBuffer = 1;        // Mélange les meshbuffers ayant le même matériel.
    loadParam.cleanUnResolvedMeshes = 1;    // Les meshs irrésolues devraient être nettoyées. Sinon texture bleue.
    loadParam.loadAllShaders = 1;           // Charge tous les scripts du dossier de script.
    loadParam.loadSkyShader = 0;            // Charge skyShader
    loadParam.alpharef = 1;

    sound = 0;

    CurrentMapName = "";
    CurrentArchiveList.clear ();

    // Dossier média de l'explorateur.
    CurrentArchiveList.push_back ( StartupDir + "../../media/" );

    // Ajoute les fichiers originaux de Quake 3 avant que vous ne chargiez vos cartes personnalisées.
    // La plupart des mods utilisent les shaders, modèles, objets et armes originaux.
    CurrentArchiveList.push_back("/q/baseq3/");

    CurrentArchiveList.push_back(StartupDir + "../../media/map-20kdm2.pk3");
}

Charge l'état du jeu à partir d'un fichier cfg typique de Quake3.

 
Sélectionnez
s32 GameData::load ( const path &filename )
{
    if (!Device)
        return 0;

    // Le chargeur de mesh Quake 3 peut aussi gérer les fichiers *.shader et *.cfg.
    IQ3LevelMesh* mesh = (IQ3LevelMesh*) Device->getSceneManager()->getMesh ( filename );
    if (!mesh)
        return 0;

    tQ3EntityList &entityList = mesh->getEntityList ();

    stringc s;
    u32 pos;

    for ( u32 e = 0; e != entityList.size (); ++e )
    {
        //dumpShader ( s, &entityList[e], false );
        //printf ( s.c_str () );

        for ( u32 g = 0; g != entityList[e].getGroupSize (); ++g )
        {
            const SVarGroup *group = entityList[e].getGroup ( g );

            for ( u32 index = 0; index < group->Variable.size (); ++index )
            {
                const SVariable &v = group->Variable[index];
                pos = 0;
                if ( v.name == "playerposition" )
                {
                    PlayerPosition = getAsVector3df ( v.content, pos );
                }
                else
                if ( v.name == "playerrotation" )
                {
                    PlayerRotation = getAsVector3df ( v.content, pos );
                }
            }
        }
    }

    return 1;
}

Stocke l'état courant du jeu dans un fichier de configuration de Quake 3.

 
Sélectionnez
s32 GameData::save ( const path &filename )
{
    return 0;
    if (!Device)
        return 0;

    c8 buf[128];
    u32 i;

    // Stocke l'archive courante pour recommencer.
    CurrentArchiveList.clear();
    IFileSystem *fs = Device->getFileSystem();
    for ( i = 0; i != fs->getFileArchiveCount(); ++i )
    {
        CurrentArchiveList.push_back ( fs->getFileArchive(i)->getFileList()->getPath() );
    }

    // Stocke la position et la rotation du joueur.
    ICameraSceneNode * camera = Device->getSceneManager()->getActiveCamera ();
    if ( camera )
    {
        PlayerPosition = camera->getPosition ();
        PlayerRotation = camera->getRotation ();
    }

    IWriteFile *file = fs->createAndWriteFile ( filename );
    if (!file)
        return 0;

    snprintf ( buf, 128, "playerposition %.f %.f %.f\nplayerrotation %.f %.f %.f\n",
            PlayerPosition.X, PlayerPosition.Z, PlayerPosition.Y,
            PlayerRotation.X, PlayerRotation.Z, PlayerRotation.Y);
    file->write ( buf, (s32) strlen ( buf ) );
    for ( i = 0; i != fs->getFileArchiveCount(); ++i )
    {
        snprintf ( buf, 128, "archive %s\n",stringc ( fs->getFileArchive(i)->getFileList()->getPath() ).c_str () );
        file->write ( buf, (s32) strlen ( buf ) );
    }

    file->drop ();
    return 1;
}

II. Joueur

Représente un joueur.

 
Sélectionnez
struct Q3Player : public IAnimationEndCallBack
{
    Q3Player ()
    : Device(0), MapParent(0), Mesh(0), WeaponNode(0), StartPositionCurrent(0)
    {
        animation[0] = 0;
        memset(Anim, 0, sizeof(TimeFire)*4);
    }

    virtual void OnAnimationEnd(IAnimatedMeshSceneNode* node);

    void create (   IrrlichtDevice *device,
                    IQ3LevelMesh* mesh,
                    ISceneNode *mapNode,
                    IMetaTriangleSelector *meta
                );
    void shutdown ();
    void setAnim ( const c8 *name );
    void respawn ();
    void setpos ( const vector3df &pos, const vector3df& rotation );

    ISceneNodeAnimatorCollisionResponse * cam() { return camCollisionResponse ( Device ); }

    IrrlichtDevice *Device;
    ISceneNode* MapParent;
    IQ3LevelMesh* Mesh;
    IAnimatedMeshSceneNode* WeaponNode;
    s32 StartPositionCurrent;
    TimeFire Anim[4];
    c8 animation[64];
    c8 buf[64];
};

Fin du joueur.

 
Sélectionnez
void Q3Player::shutdown ()
{
    setAnim ( 0 );

    dropElement (WeaponNode);

    if ( Device )
    {
        ICameraSceneNode* camera = Device->getSceneManager()->getActiveCamera();
        dropElement ( camera );
        Device = 0;
    }

    MapParent = 0;
    Mesh = 0;
}

Crée un nouveau joueur.

 
Sélectionnez
void Q3Player::create ( IrrlichtDevice *device, IQ3LevelMesh* mesh, ISceneNode *mapNode, IMetaTriangleSelector *meta )
{
    setTimeFire ( Anim + 0, 200, FIRED );
    setTimeFire ( Anim + 1, 5000 );

    if (!device)
        return;
    // Attache l'arme FPS à la caméra.
    Device = device;
    Mesh = mesh;
    MapParent = mapNode;

    ISceneManager *smgr = device->getSceneManager ();
    IVideoDriver * driver = device->getVideoDriver();

    ICameraSceneNode* camera = 0;

    SKeyMap keyMap[10];
    keyMap[0].Action = EKA_MOVE_FORWARD;
    keyMap[0].KeyCode = KEY_UP;
    keyMap[1].Action = EKA_MOVE_FORWARD;
    keyMap[1].KeyCode = KEY_KEY_W;

    keyMap[2].Action = EKA_MOVE_BACKWARD;
    keyMap[2].KeyCode = KEY_DOWN;
    keyMap[3].Action = EKA_MOVE_BACKWARD;
    keyMap[3].KeyCode = KEY_KEY_S;

    keyMap[4].Action = EKA_STRAFE_LEFT;
    keyMap[4].KeyCode = KEY_LEFT;
    keyMap[5].Action = EKA_STRAFE_LEFT;
    keyMap[5].KeyCode = KEY_KEY_A;

    keyMap[6].Action = EKA_STRAFE_RIGHT;
    keyMap[6].KeyCode = KEY_RIGHT;
    keyMap[7].Action = EKA_STRAFE_RIGHT;
    keyMap[7].KeyCode = KEY_KEY_D;

    keyMap[8].Action = EKA_JUMP_UP;
    keyMap[8].KeyCode = KEY_KEY_J;

    keyMap[9].Action = EKA_CROUCH;
    keyMap[9].KeyCode = KEY_KEY_C;

    camera = smgr->addCameraSceneNodeFPS(0, 100.0f, 0.6f, -1, keyMap, 10, false, 0.6f);
    camera->setName ( "First Person Camera" );
    //camera->setFOV ( 100.f * core::DEGTORAD );
    camera->setFarValue( 20000.f );

    IAnimatedMeshMD2* weaponMesh = (IAnimatedMeshMD2*) smgr->getMesh("gun.md2");
    if ( 0 == weaponMesh )
        return;

    if ( weaponMesh->getMeshType() == EAMT_MD2 )
    {
        s32 count = weaponMesh->getAnimationCount();
        for ( s32 i = 0; i != count; ++i )
        {
            snprintf ( buf, 64, "Animation: %s", weaponMesh->getAnimationName(i) );
            device->getLogger()->log(buf, ELL_INFORMATION);
        }
    }

    WeaponNode = smgr->addAnimatedMeshSceneNode(
                        weaponMesh,
                        smgr->getActiveCamera(),
                        10,
                        vector3df( 0, 0, 0),
                        vector3df(-90,-90,90)
                        );
    WeaponNode->setMaterialFlag(EMF_LIGHTING, false);
    WeaponNode->setMaterialTexture(0, driver->getTexture( "gun.jpg"));
    WeaponNode->setLoopMode ( false );
    WeaponNode->setName ( "tommi the gun man" );

    // Crée un animateur automatique de réponse aux collisions.
    ISceneNodeAnimator* anim =
        smgr->createCollisionResponseAnimator( meta, camera,
            vector3df(30,45,30),
            getGravity ( "earth" ),
            vector3df(0,40,0),
            0.0005f
        );

    camera->addAnimator( anim );
    anim->drop();

    if ( meta )
    {
        meta->drop ();
    }

    respawn ();
    setAnim ( "idle" );
}

III. Position de départ et caméra

Nous avons besoin d'une bonne position de départ dans le niveau. Nous pouvons demander au chargeur Quake3 toutes les entités avec class_name valant "info_player_deathmatch".

 
Sélectionnez
void Q3Player::respawn ()
{
    if (!Device)
        return;
    ICameraSceneNode* camera = Device->getSceneManager()->getActiveCamera();

    Device->getLogger()->log( "respawn" );

    if ( StartPositionCurrent >= Q3StartPosition (
            Mesh, camera,StartPositionCurrent++,
            cam ()->getEllipsoidTranslation() )
        )
    {
        StartPositionCurrent = 0;
    }
}

Détermine la position du joueur à partir des coordonnées enregistrées.

 
Sélectionnez
void Q3Player::setpos ( const vector3df &pos, const vector3df &rotation )
{
    if (!Device)
        return;
    Device->getLogger()->log( "setpos" );

    ICameraSceneNode* camera = Device->getSceneManager()->getActiveCamera();
    if ( camera )
    {
        camera->setPosition ( pos );
        camera->setRotation ( rotation );
        camera->OnAnimate ( 0 );
    }
}

Définit l'animation du joueur et de l'arme.

 
Sélectionnez
void Q3Player::setAnim ( const c8 *name )
{
    if ( name )
    {
        snprintf ( animation, 64, "%s", name );
        if ( WeaponNode )
        {
            WeaponNode->setAnimationEndCallback ( this );
            WeaponNode->setMD2Animation ( animation );
        }
    }
    else
    {
        animation[0] = 0;
        if ( WeaponNode )
        {
            WeaponNode->setAnimationEndCallback ( 0 );
        }
    }
}


// Callback
void Q3Player::OnAnimationEnd(IAnimatedMeshSceneNode* node)
{
    setAnim ( 0 );
}

Éléments d'interface utilisateur.

 
Sélectionnez
struct GUI
{
    GUI ()
    {
        memset ( this, 0, sizeof ( *this ) );
    }

    void drop()
    {
        dropElement ( Window );
        dropElement ( Logo );
    }

    IGUIComboBox* VideoDriver;
    IGUIComboBox* VideoMode;
    IGUICheckBox* FullScreen;
    IGUICheckBox* Bit32;
    IGUIScrollBar* MultiSample;
    IGUIButton* SetVideoMode;

    IGUIScrollBar* Tesselation;
    IGUIScrollBar* Gamma;
    IGUICheckBox* Collision;
    IGUICheckBox* Visible_Map;
    IGUICheckBox* Visible_Shader;
    IGUICheckBox* Visible_Fog;
    IGUICheckBox* Visible_Unresolved;
    IGUICheckBox* Visible_Skydome;
    IGUIButton* Respawn;

    IGUITable* ArchiveList;
    IGUIButton* ArchiveAdd;
    IGUIButton* ArchiveRemove;
    IGUIFileOpenDialog* ArchiveFileOpen;
    IGUIButton* ArchiveUp;
    IGUIButton* ArchiveDown;

    IGUIListBox* MapList;
    IGUITreeView* SceneTree;
    IGUIStaticText* StatusLine;
    IGUIImage* Logo;
    IGUIWindow* Window;
};

IV. Construction de la scène

CQuake3EventHandler contrôle le jeu.

 
Sélectionnez
class CQuake3EventHandler : public IEventReceiver
{
public:

    CQuake3EventHandler( GameData *gameData );
    virtual ~CQuake3EventHandler ();

    void Animate();
    void Render();

    void AddArchive ( const path& archiveName );
    void LoadMap ( const stringw& mapName, s32 collision );
    void CreatePlayers();
    void AddSky( u32 dome, const c8 *texture );
    Q3Player *GetPlayer ( u32 index ) { return &Player[index]; }

    void CreateGUI();
    void SetGUIActive( s32 command);

    bool OnEvent(const SEvent& eve);


private:

    GameData *Game;

    IQ3LevelMesh* Mesh;
    ISceneNode* MapParent;
    ISceneNode* ShaderParent;
    ISceneNode* ItemParent;
    ISceneNode* UnresolvedParent;
    ISceneNode* BulletParent;
    ISceneNode* FogParent;
    ISceneNode * SkyNode;
    IMetaTriangleSelector *Meta;

    c8 buf[256];

    Q3Player Player[2];

    struct SParticleImpact
    {
        u32 when;
        vector3df pos;
        vector3df outVector;
    };
    array<SParticleImpact> Impacts;
    void useItem( Q3Player * player);
    void createParticleImpacts( u32 now );

    void createTextures ();
    void addSceneTreeItem( ISceneNode * parent, IGUITreeViewNode* nodeParent);

    GUI gui;
    void dropMap ();
};

Constructeur.

 
Sélectionnez
CQuake3EventHandler::CQuake3EventHandler( GameData *game )
: Game(game), Mesh(0), MapParent(0), ShaderParent(0), ItemParent(0), UnresolvedParent(0),
    BulletParent(0), FogParent(0), SkyNode(0), Meta(0)
{
    buf[0]=0;
    // Utilise aussi des textures sur 16 bits pour un RenderDevice 16 bits.
    if ( Game->deviceParam.Bits == 16 )
    {
        game->Device->getVideoDriver()->setTextureCreationFlag(ETCF_ALWAYS_16_BIT, true);
    }

    // Contrôle l'écriture du tampon de profondeur pour les shaders de Quake3.
    game->Device->getSceneManager()->getParameters()->setAttribute(scene::ALLOW_ZWRITE_ON_TRANSPARENT, true);

    // Crée des textures internes.
    createTextures ();

    sound_init ( game->Device );

    Game->Device->setEventReceiver ( this );
}


// Destructeur
CQuake3EventHandler::~CQuake3EventHandler ()
{
    Player[0].shutdown ();
    sound_shutdown ();

    Game->save( "explorer.cfg" );

    Game->Device->drop();
}


// Crée des textures de nuages et de brouillard à l'exécution.
void CQuake3EventHandler::createTextures()
{
    IVideoDriver * driver = Game->Device->getVideoDriver();

    dimension2du dim(64, 64);

    video::IImage* image;
    u32 i;
    u32 x;
    u32 y;
    u32 * data;
    for ( i = 0; i != 8; ++i )
    {
        image = driver->createImage ( video::ECF_A8R8G8B8, dim);
        data = (u32*) image->lock ();
        for ( y = 0; y != dim.Height; ++y )
        {
            for ( x = 0; x != dim.Width; ++x )
            {
                data [x] = 0xFFFFFFFF;
            }
            data = (u32*) ( (u8*) data + image->getPitch() );
        }
        image->unlock();
        snprintf ( buf, 64, "smoke_%02d", i );
        driver->addTexture( buf, image );
        image->drop ();
    }

    // Brouillard
    for ( i = 0; i != 1; ++i )
    {
        image = driver->createImage ( video::ECF_A8R8G8B8, dim);
        data = (u32*) image->lock ();
        for ( y = 0; y != dim.Height; ++y )
        {
            for ( x = 0; x != dim.Width; ++x )
            {
                data [x] = 0xFFFFFFFF;
            }
            data = (u32*) ( (u8*) data + image->getPitch() );
        }
        image->unlock();
        snprintf ( buf, 64, "fog_%02d", i );
        driver->addTexture( buf, image );
        image->drop ();
    }
}

V. Interface utilisateur

Crée l'interface utilisateur.

 
Sélectionnez
void CQuake3EventHandler::CreateGUI()
{

    IGUIEnvironment *env = Game->Device->getGUIEnvironment();
    IVideoDriver * driver = Game->Device->getVideoDriver();

    gui.drop();

    // Met la police du skin.
    IGUIFont* font = env->getFont("fontlucida.png");
    if (font)
        env->getSkin()->setFont(font);
    env->getSkin()->setColor ( EGDC_BUTTON_TEXT, video::SColor(240,0xAA,0xAA,0xAA) );
    env->getSkin()->setColor ( EGDC_3D_HIGH_LIGHT, video::SColor(240,0x22,0x22,0x22) );
    env->getSkin()->setColor ( EGDC_3D_FACE, video::SColor(240,0x44,0x44,0x44) );
    env->getSkin()->setColor ( EGDC_EDITABLE, video::SColor(240,0x44,0x44,0x44) );
    env->getSkin()->setColor ( EGDC_FOCUSED_EDITABLE, video::SColor(240,0x54,0x54,0x54) );
    env->getSkin()->setColor ( EGDC_WINDOW, video::SColor(240,0x66,0x66,0x66) );

    // Taille minimale de l'interface utilisateur 800x600
    dimension2d<u32> dim ( 800, 600 );
    dimension2d<u32> vdim ( Game->Device->getVideoDriver()->getScreenSize() );

    if ( vdim.Height >= dim.Height && vdim.Width >= dim.Width )
    {
        //dim = vdim;
    }
    else
    {
    }

    gui.Window = env->addWindow ( rect<s32> ( 0, 0, dim.Width, dim.Height ), false, L"Quake3 Explorer" );
    gui.Window->setToolTipText ( L"Quake3Explorer. Loads and show various BSP File Format and Shaders." );
    gui.Window->getCloseButton()->setToolTipText ( L"Quit Quake3 Explorer" );

    // Ajoute une ligne de statut pour un texte d'aide.
    gui.StatusLine = env->addStaticText( 0, rect<s32>( 5,dim.Height - 30,dim.Width - 5,dim.Height - 10),
                                false, false, gui.Window, -1, true
                            );


    env->addStaticText ( L"VideoDriver:", rect<s32>( dim.Width - 400, 24, dim.Width - 310, 40 ),false, false, gui.Window, -1, false );
    gui.VideoDriver = env->addComboBox(rect<s32>( dim.Width - 300, 24, dim.Width - 10, 40 ),gui.Window);
    gui.VideoDriver->addItem(L"Direct3D 9.0c", EDT_DIRECT3D9 );
    gui.VideoDriver->addItem(L"Direct3D 8.1", EDT_DIRECT3D8 );
    gui.VideoDriver->addItem(L"OpenGL 1.5", EDT_OPENGL);
    gui.VideoDriver->addItem(L"Software Renderer", EDT_SOFTWARE);
    gui.VideoDriver->addItem(L"Burning's Video (TM) Thomas Alten", EDT_BURNINGSVIDEO);
    gui.VideoDriver->setSelected ( gui.VideoDriver->getIndexForItemData ( Game->deviceParam.DriverType ) );
    gui.VideoDriver->setToolTipText ( L"Use a VideoDriver" );

    env->addStaticText ( L"VideoMode:", rect<s32>( dim.Width - 400, 44, dim.Width - 310, 60 ),false, false, gui.Window, -1, false );
    gui.VideoMode = env->addComboBox(rect<s32>( dim.Width - 300, 44, dim.Width - 10, 60 ),gui.Window);
    gui.VideoMode->setToolTipText ( L"Supported Screenmodes" );
    IVideoModeList *modeList = Game->Device->getVideoModeList();
    if ( modeList )
    {
        s32 i;
        for ( i = 0; i != modeList->getVideoModeCount (); ++i )
        {
            u16 d = modeList->getVideoModeDepth ( i );
            if ( d < 16 )
                continue;

            u16 w = modeList->getVideoModeResolution ( i ).Width;
            u16 h = modeList->getVideoModeResolution ( i ).Height;
            u32 val = w << 16 | h;

            if ( gui.VideoMode->getIndexForItemData ( val ) >= 0 )
                continue;

            f32 aspect = (f32) w / (f32) h;
            const c8 *a = "";
            if ( core::equals ( aspect, 1.3333333333f ) ) a = "4:3";
            else if ( core::equals ( aspect, 1.6666666f ) ) a = "15:9 widescreen";
            else if ( core::equals ( aspect, 1.7777777f ) ) a = "16:9 widescreen";
            else if ( core::equals ( aspect, 1.6f ) ) a = "16:10 widescreen";
            else if ( core::equals ( aspect, 2.133333f ) ) a = "20:9 widescreen";

            snprintf ( buf, sizeof ( buf ), "%d x %d, %s",w, h, a );
            gui.VideoMode->addItem ( stringw ( buf ).c_str(), val );
        }
    }
    gui.VideoMode->setSelected ( gui.VideoMode->getIndexForItemData (
                                    Game->deviceParam.WindowSize.Width << 16 |
                                    Game->deviceParam.WindowSize.Height ) );

    gui.FullScreen = env->addCheckBox ( Game->deviceParam.Fullscreen, rect<s32>( dim.Width - 400, 64, dim.Width - 300, 80 ), gui.Window,-1, L"Fullscreen" );
    gui.FullScreen->setToolTipText ( L"Set Fullscreen or Window Mode" );

    gui.Bit32 = env->addCheckBox ( Game->deviceParam.Bits == 32, rect<s32>( dim.Width - 300, 64, dim.Width - 240, 80 ), gui.Window,-1, L"32Bit" );
    gui.Bit32->setToolTipText ( L"Use 16 or 32 Bit" );

    env->addStaticText ( L"MultiSample:", rect<s32>( dim.Width - 235, 64, dim.Width - 150, 80 ),false, false, gui.Window, -1, false );
    gui.MultiSample = env->addScrollBar( true, rect<s32>( dim.Width - 150, 64, dim.Width - 70, 80 ), gui.Window,-1 );
    gui.MultiSample->setMin ( 0 );
    gui.MultiSample->setMax ( 8 );
    gui.MultiSample->setSmallStep ( 1 );
    gui.MultiSample->setLargeStep ( 1 );
    gui.MultiSample->setPos ( Game->deviceParam.AntiAlias );
    gui.MultiSample->setToolTipText ( L"Set the MultiSample (disable, 1x, 2x, 4x, 8x )" );

    gui.SetVideoMode = env->addButton (rect<s32>( dim.Width - 60, 64, dim.Width - 10, 80 ), gui.Window, -1,L"set" );
    gui.SetVideoMode->setToolTipText ( L"Set Video Mode with current values" );

    env->addStaticText ( L"Gamma:", rect<s32>( dim.Width - 400, 104, dim.Width - 310, 120 ),false, false, gui.Window, -1, false );
    gui.Gamma = env->addScrollBar( true, rect<s32>( dim.Width - 300, 104, dim.Width - 10, 120 ), gui.Window,-1 );
    gui.Gamma->setMin ( 50 );
    gui.Gamma->setMax ( 350 );
    gui.Gamma->setSmallStep ( 1 );
    gui.Gamma->setLargeStep ( 10 );
    gui.Gamma->setPos ( core::floor32 ( Game->GammaValue * 100.f ) );
    gui.Gamma->setToolTipText ( L"Adjust Gamma Ramp ( 0.5 - 3.5)" );
    Game->Device->setGammaRamp ( Game->GammaValue, Game->GammaValue, Game->GammaValue, 0.f, 0.f );


    env->addStaticText ( L"Tesselation:", rect<s32>( dim.Width - 400, 124, dim.Width - 310, 140 ),false, false, gui.Window, -1, false );
    gui.Tesselation = env->addScrollBar( true, rect<s32>( dim.Width - 300, 124, dim.Width - 10, 140 ), gui.Window,-1 );
    gui.Tesselation->setMin ( 2 );
    gui.Tesselation->setMax ( 12 );
    gui.Tesselation->setSmallStep ( 1 );
    gui.Tesselation->setLargeStep ( 1 );
    gui.Tesselation->setPos ( Game->loadParam.patchTesselation );
    gui.Tesselation->setToolTipText ( L"How smooth should curved surfaces be rendered" );

    gui.Collision = env->addCheckBox ( true, rect<s32>( dim.Width - 400, 150, dim.Width - 300, 166 ), gui.Window,-1, L"Collision" );
    gui.Collision->setToolTipText ( L"Set collision on or off ( flythrough ). \nPress F7 on your Keyboard" );
    gui.Visible_Map = env->addCheckBox ( true, rect<s32>( dim.Width - 300, 150, dim.Width - 240, 166 ), gui.Window,-1, L"Map" );
    gui.Visible_Map->setToolTipText ( L"Show or not show the static part the Level. \nPress F3 on your Keyboard" );
    gui.Visible_Shader = env->addCheckBox ( true, rect<s32>( dim.Width - 240, 150, dim.Width - 170, 166 ), gui.Window,-1, L"Shader" );
    gui.Visible_Shader->setToolTipText ( L"Show or not show the Shader Nodes. \nPress F4 on your Keyboard" );
    gui.Visible_Fog = env->addCheckBox ( true, rect<s32>( dim.Width - 170, 150, dim.Width - 110, 166 ), gui.Window,-1, L"Fog" );
    gui.Visible_Fog->setToolTipText ( L"Show or not show the Fog Nodes. \nPress F5 on your Keyboard" );
    gui.Visible_Unresolved = env->addCheckBox ( true, rect<s32>( dim.Width - 110, 150, dim.Width - 10, 166 ), gui.Window,-1, L"Unresolved" );
    gui.Visible_Unresolved->setToolTipText ( L"Show the or not show the Nodes the Engine can't handle. \nPress F6 on your Keyboard" );
    gui.Visible_Skydome = env->addCheckBox ( true, rect<s32>( dim.Width - 110, 180, dim.Width - 10, 196 ), gui.Window,-1, L"Skydome" );
    gui.Visible_Skydome->setToolTipText ( L"Show the or not show the Skydome." );

    //Respawn = env->addButton ( rect<s32>( dim.Width - 260, 90, dim.Width - 10, 106 ), 0,-1, L"Respawn" );

    env->addStaticText ( L"Archives:", rect<s32>( 5, dim.Height - 530, dim.Width - 600,dim.Height - 514 ),false, false, gui.Window, -1, false );

    gui.ArchiveAdd = env->addButton ( rect<s32>( dim.Width - 725, dim.Height - 530, dim.Width - 665, dim.Height - 514 ), gui.Window,-1, L"add" );
    gui.ArchiveAdd->setToolTipText ( L"Add an archive, usually packed zip-archives (*.pk3) to the Filesystem" );
    gui.ArchiveRemove = env->addButton ( rect<s32>( dim.Width - 660, dim.Height - 530, dim.Width - 600, dim.Height - 514 ), gui.Window,-1, L"del" );
    gui.ArchiveRemove->setToolTipText ( L"Remove the selected archive from the FileSystem." );
    gui.ArchiveUp = env->addButton ( rect<s32>( dim.Width - 575, dim.Height - 530, dim.Width - 515, dim.Height - 514 ), gui.Window,-1, L"up" );
    gui.ArchiveUp->setToolTipText ( L"Arrange Archive Look-up Hirachy. Move the selected Archive up" );
    gui.ArchiveDown = env->addButton ( rect<s32>( dim.Width - 510, dim.Height - 530, dim.Width - 440, dim.Height - 514 ), gui.Window,-1, L"down" );
    gui.ArchiveDown->setToolTipText ( L"Arrange Archive Look-up Hirachy. Move the selected Archive down" );


    gui.ArchiveList = env->addTable ( rect<s32>( 5,dim.Height - 510, dim.Width - 450,dim.Height - 410 ), gui.Window  );
    gui.ArchiveList->addColumn ( L"Type", 0 );
    gui.ArchiveList->addColumn ( L"Real File Path", 1 );
    gui.ArchiveList->setColumnWidth ( 0, 60 );
    gui.ArchiveList->setColumnWidth ( 1, 284 );
    gui.ArchiveList->setToolTipText ( L"Show the attached Archives" );


    env->addStaticText ( L"Maps:", rect<s32>( 5, dim.Height - 400, dim.Width - 450,dim.Height - 380 ),false, false, gui.Window, -1, false );
    gui.MapList = env->addListBox ( rect<s32>( 5,dim.Height - 380, dim.Width - 450,dim.Height - 40  ), gui.Window, -1, true  );
    gui.MapList->setToolTipText ( L"Show the current Maps in all Archives.\n Double-Click the Map to start the level" );


    // Crée un arbre de scène visible.
    env->addStaticText ( L"Scenegraph:", rect<s32>( dim.Width - 400, dim.Height - 400, dim.Width - 5,dim.Height - 380 ),false, false, gui.Window, -1, false );
    gui.SceneTree = env->addTreeView(   rect<s32>( dim.Width - 400, dim.Height - 380, dim.Width - 5, dim.Height - 40 ),
                                    gui.Window, -1, true, true, false );
    gui.SceneTree->setToolTipText ( L"Show the current Scenegraph" );
    gui.SceneTree->getRoot()->clearChildren();
    addSceneTreeItem ( Game->Device->getSceneManager()->getRootSceneNode(), gui.SceneTree->getRoot() );


    IGUIImageList* imageList = env->createImageList(    driver->getTexture ( "iconlist.png" ),
                                        dimension2di( 32, 32 ), true );

    if ( imageList )
    {
        gui.SceneTree->setImageList( imageList );
        imageList->drop ();
    }


    // Charge le logo du moteur.
    gui.Logo = env->addImage( driver->getTexture("irrlichtlogo3.png"), position2d<s32>(5, 16 ), true, 0 );
    gui.Logo->setToolTipText ( L"The great Irrlicht Engine" );

    AddArchive ( "" );
}

Ajoute une archive au système de fichier et met à jour l'interface utilisateur.

 
Sélectionnez
void CQuake3EventHandler::AddArchive ( const path& archiveName )
{
    IFileSystem *fs = Game->Device->getFileSystem();
    u32 i;

    if ( archiveName.size () )
    {
        bool exists = false;
        for ( i = 0; i != fs->getFileArchiveCount(); ++i )
        {
            if ( fs->getFileArchive(i)->getFileList()->getPath() == archiveName )
            {
                exists = true;
                break;
            }
        }

        if (!exists)
        {
            fs->addFileArchive(archiveName, true, false);
        }
    }

    // Stocke l'archive courante dans les données de jeux.
    // Montre l'archive attachée dans le bon ordre.
    if ( gui.ArchiveList )
    {
        gui.ArchiveList->clearRows();

        for ( i = 0; i != fs->getFileArchiveCount(); ++i )
        {
            IFileArchive * archive = fs->getFileArchive ( i );

            u32 index = gui.ArchiveList->addRow(i);

            core::stringw typeName;
            switch(archive->getType())
            {
            case io::EFAT_ZIP:
                typeName = "ZIP";
                break;
            case io::EFAT_GZIP:
                typeName = "gzip";
                break;
            case io::EFAT_FOLDER:
                typeName = "Mount";
                break;
            case io::EFAT_PAK:
                typeName = "PAK";
                break;
            case io::EFAT_TAR:
                typeName = "TAR";
                break;
            default:
                typeName = "archive";
            }

            gui.ArchiveList->setCellText ( index, 0, typeName );
            gui.ArchiveList->setCellText ( index, 1, archive->getFileList()->getPath() );
        }
    }


    // Parcourt les archives des cartes.
    if ( gui.MapList )
    {
        gui.MapList->clear();

        IGUISpriteBank *bank = Game->Device->getGUIEnvironment()->getSpriteBank("sprite_q3map");
        if ( 0 == bank )
            bank = Game->Device->getGUIEnvironment()->addEmptySpriteBank("sprite_q3map");

        SGUISprite sprite;
        SGUISpriteFrame frame;
        core::rect<s32> r;

        bank->getSprites().clear();
        bank->getPositions().clear ();
        gui.MapList->setSpriteBank ( bank );

        u32 g = 0;
        core::stringw s;

        // Parcourt le système de fichiers attachés.
        fs->setFileListSystem ( FILESYSTEM_VIRTUAL );
        fs->changeWorkingDirectoryTo ( "/maps/" );
        IFileList *fileList = fs->createFileList ();
        fs->setFileListSystem ( FILESYSTEM_NATIVE );

        for ( i=0; i< fileList->getFileCount(); ++i)
        {
            s = fileList->getFullFileName(i);
            if ( s.find ( ".bsp" ) >= 0 )
            {
                // Obtient la capture d'écran du niveau, le redimensionne en une texture de 128x128.
                path c ( s );
                deletePathFromFilename ( c );
                cutFilenameExtension ( c, c );
                c = path ( "levelshots/" ) + c;

                dimension2du dim ( 128, 128 );
                IVideoDriver * driver = Game->Device->getVideoDriver();
                IImage* image = 0;
                ITexture *tex = 0;
                path filename;

                filename = c + ".jpg";
                if ( fs->existFile ( filename ) )
                    image = driver->createImageFromFile( filename );
                if ( 0 == image )
                {
                    filename = c + ".tga";
                    if ( fs->existFile ( filename ) )
                        image = driver->createImageFromFile( filename );
                }

                if ( image )
                {
                    IImage* filter = driver->createImage ( video::ECF_R8G8B8, dim );
                    image->copyToScalingBoxFilter ( filter, 0 );
                    image->drop ();
                    image = filter;
                }

                if ( image )
                {
                    tex = driver->addTexture ( filename, image );
                    image->drop ();
                }


                bank->setTexture ( g, tex );

                r.LowerRightCorner.X = dim.Width;
                r.LowerRightCorner.Y = dim.Height;
                gui.MapList->setItemHeight ( r.LowerRightCorner.Y + 4 );
                frame.rectNumber = bank->getPositions().size();
                frame.textureNumber = g;

                bank->getPositions().push_back(r);

                sprite.Frames.set_used ( 0 );
                sprite.Frames.push_back(frame);
                sprite.frameTime = 0;
                bank->getSprites().push_back(sprite);

                gui.MapList->addItem ( s.c_str (), g );
                g += 1;
            }
        }
        fileList->drop ();

        gui.MapList->setSelected ( -1 );
        IGUIScrollBar * bar = (IGUIScrollBar*)gui.MapList->getElementFromId( 0 );
        if ( bar )
            bar->setPos ( 0 );

    }

}

VI. Cartes

Efface la carte en mémoire.

 
Sélectionnez
void CQuake3EventHandler::dropMap ()
{
    IVideoDriver * driver = Game->Device->getVideoDriver();

    driver->removeAllHardwareBuffers ();
    driver->removeAllTextures ();

    Player[0].shutdown ();


    dropElement ( ItemParent );
    dropElement ( ShaderParent );
    dropElement ( UnresolvedParent );
    dropElement ( FogParent );
    dropElement ( BulletParent );


    Impacts.clear();

    if ( Meta )
    {
        Meta = 0;
    }

    dropElement ( MapParent );
    dropElement ( SkyNode );

    // Nettoie les meshs parce que les textures sont invalides.
    // TODO: meilleur gestionnaire de textures;-)
    IMeshCache *cache = Game->Device->getSceneManager ()->getMeshCache();
    cache->clear ();
    Mesh = 0;
}

Charge une nouvelle carte.

 
Sélectionnez
void CQuake3EventHandler::LoadMap ( const stringw &mapName, s32 collision )
{
    if ( 0 == mapName.size() )
        return;

    dropMap ();

    IFileSystem *fs = Game->Device->getFileSystem();
    ISceneManager *smgr = Game->Device->getSceneManager ();

    IReadFile* file = fs->createMemoryReadFile(&Game->loadParam,
                sizeof(Game->loadParam), L"levelparameter.cfg", false);

    // Charge un fichier cfg.
    smgr->getMesh( file );
    file->drop ();

    // Charge la carte actuelle.
    Mesh = (IQ3LevelMesh*) smgr->getMesh(mapName);
    if ( 0 == Mesh )
        return;

Ajoute le mesh de géométrie à la scène (polygones et patchs). Le mesh de géométrie est optimisé pour le dessin rapide.

 
Sélectionnez
    IMesh *geometry = Mesh->getMesh(E_Q3_MESH_GEOMETRY);
    if ( 0 == geometry || geometry->getMeshBufferCount() == 0)
        return;

    Game->CurrentMapName = mapName;

    // Crée une liste de collisions.
    Meta = 0;

    ITriangleSelector * selector = 0;
    if (collision)
        Meta = smgr->createMetaTriangleSelector();

    //IMeshBuffer *b0 = geometry->getMeshBuffer(0);
    //s32 minimalNodes = b0 ? core::s32_max ( 2048, b0->getVertexCount() / 32 ) : 2048;
    s32 minimalNodes = 2048;

    MapParent = smgr->addOctreeSceneNode(geometry, 0, -1, minimalNodes);
    MapParent->setName ( mapName );
    if ( Meta )
    {
        selector = smgr->createOctreeTriangleSelector( geometry,MapParent, minimalNodes);
        //selector = smgr->createTriangleSelector ( geometry, MapParent );
        Meta->addTriangleSelector( selector);
        selector->drop ();
    }

    // Parent logique pour les objets.
    ItemParent = smgr->addEmptySceneNode();
    if ( ItemParent )
        ItemParent->setName ( "Item Container" );

    ShaderParent = smgr->addEmptySceneNode();
    if ( ShaderParent )
        ShaderParent->setName ( "Shader Container" );

    UnresolvedParent = smgr->addEmptySceneNode();
    if ( UnresolvedParent )
        UnresolvedParent->setName ( "Unresolved Container" );

    FogParent = smgr->addEmptySceneNode();
    if ( FogParent )
        FogParent->setName ( "Fog Container" );

    // Parent logique pour les projectiles.
    BulletParent = smgr->addEmptySceneNode();
    if ( BulletParent )
        BulletParent->setName ( "Bullet Container" );

VII. Nœuds de scènes

Maintenant, construisons un nœud de scène pour chaque shader. Les objets sont stockés dans le mesh de Quake E_Q3_MESH_ITEMS et les identifiants de shaders sont stockés dans le MaterialParameters surtout des crânes sombres et de la lave mouvante… ou des tubes vert flashy ?

 
Sélectionnez
    Q3ShaderFactory ( Game->loadParam, Game->Device, Mesh, E_Q3_MESH_ITEMS,ShaderParent, Meta, false );
    Q3ShaderFactory ( Game->loadParam, Game->Device, Mesh, E_Q3_MESH_FOG,FogParent, 0, false );
    Q3ShaderFactory ( Game->loadParam, Game->Device, Mesh, E_Q3_MESH_UNRESOLVED,UnresolvedParent, Meta, true );

Maintenant construit les modèles à partir de la liste d'entrées.

 
Sélectionnez
    Q3ModelFactory ( Game->loadParam, Game->Device, Mesh, ItemParent, false );
}

Ajoute un nœud de scène avec une icône à l'arbre de scène.

 
Sélectionnez
void CQuake3EventHandler::addSceneTreeItem( ISceneNode * parent, IGUITreeViewNode* nodeParent)
{
    IGUITreeViewNode* node;
    wchar_t msg[128];

    s32 imageIndex;
    list<ISceneNode*>::ConstIterator it = parent->getChildren().begin();
    for (; it != parent->getChildren().end(); ++it)
    {
        switch ( (*it)->getType () )
        {
            case ESNT_Q3SHADER_SCENE_NODE: imageIndex = 0; break;
            case ESNT_CAMERA: imageIndex = 1; break;
            case ESNT_EMPTY: imageIndex = 2; break;
            case ESNT_MESH: imageIndex = 3; break;
            case ESNT_OCTREE: imageIndex = 3; break;
            case ESNT_ANIMATED_MESH: imageIndex = 4; break;
            case ESNT_SKY_BOX: imageIndex = 5; break;
            case ESNT_BILLBOARD: imageIndex = 6; break;
            case ESNT_PARTICLE_SYSTEM: imageIndex = 7; break;
            case ESNT_TEXT: imageIndex = 8; break;
            default:imageIndex = -1; break;
        }

        if ( imageIndex < 0 )
        {
            swprintf ( msg, 128, L"%hs,%hs",
                Game->Device->getSceneManager ()->getSceneNodeTypeName ( (*it)->getType () ),
                (*it)->getName()
                );
        }
        else
        {
            swprintf ( msg, 128, L"%hs",(*it)->getName() );
        }

        node = nodeParent->addChildBack( msg, 0, imageIndex );

        // Ajoute tous les animateurs.
        list<ISceneNodeAnimator*>::ConstIterator ait = (*it)->getAnimators().begin();
        for (; ait != (*it)->getAnimators().end(); ++ait)
        {
            imageIndex = -1;
            swprintf ( msg, 128, L"%hs",
                Game->Device->getSceneManager ()->getAnimatorTypeName ( (*ait)->getType () )
                );

            switch ( (*ait)->getType () )
            {
                case ESNAT_FLY_CIRCLE:
                case ESNAT_FLY_STRAIGHT:
                case ESNAT_FOLLOW_SPLINE:
                case ESNAT_ROTATION:
                case ESNAT_TEXTURE:
                case ESNAT_DELETION:
                case ESNAT_COLLISION_RESPONSE:
                case ESNAT_CAMERA_FPS:
                case ESNAT_CAMERA_MAYA:
                default:
                    break;
            }
            node->addChildBack( msg, 0, imageIndex );
        }

        addSceneTreeItem ( *it, node );
    }
}


// Ajoute la vie !
void CQuake3EventHandler::CreatePlayers()
{
    Player[0].create ( Game->Device, Mesh, MapParent, Meta );
}


// Ajoute un skydome à la scène.
void CQuake3EventHandler::AddSky( u32 dome, const c8 *texture)
{
    ISceneManager *smgr = Game->Device->getSceneManager ();
    IVideoDriver * driver = Game->Device->getVideoDriver();

    bool oldMipMapState = driver->getTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS);
    driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, false);

    if ( 0 == dome )
    {
        // Ordre irrlicht.
        //static const c8*p[] = { "ft", "lf", "bk", "rt", "up", "dn" };
        // Ordre quake3.
        static const c8*p[] = { "ft", "rt", "bk", "lf", "up", "dn" };

        u32 i = 0;
        snprintf ( buf, 64, "%s_%s.jpg", texture, p[i] );
        SkyNode = smgr->addSkyBoxSceneNode( driver->getTexture ( buf ), 0, 0, 0, 0, 0 );

        if (SkyNode)
        {
            for ( i = 0; i < 6; ++i )
            {
                snprintf ( buf, 64, "%s_%s.jpg", texture, p[i] );
                SkyNode->getMaterial(i).setTexture ( 0, driver->getTexture ( buf ) );
            }
        }
    }
    else
    if ( 1 == dome )
    {
        snprintf ( buf, 64, "%s.jpg", texture );
        SkyNode = smgr->addSkyDomeSceneNode(
                driver->getTexture( buf ), 32,32,
                1.f, 1.f, 1000.f, 0, 11);
    }
    else
    if ( 2 == dome )
    {
        snprintf ( buf, 64, "%s.jpg", texture );
        SkyNode = smgr->addSkyDomeSceneNode(
                driver->getTexture( buf ), 16,8,
                0.95f, 2.f, 1000.f, 0, 11);
    }

    if (SkyNode)
        SkyNode->setName("Skydome");
    //SkyNode->getMaterial(0).ZBuffer = video::EMDF_DEPTH_LESS_EQUAL;

    driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, oldMipMapState);
}


// Active les éléments d'interface utilisateur.
void CQuake3EventHandler::SetGUIActive( s32 command)
{
    bool inputState = false;

    ICameraSceneNode * camera = Game->Device->getSceneManager()->getActiveCamera ();

    switch ( command )
    {
        case 0: Game->guiActive = 0; inputState = !Game->guiActive; break;
        case 1: Game->guiActive = 1; inputState = !Game->guiActive;;break;
        case 2: Game->guiActive ^= 1; inputState = !Game->guiActive;break;
        case 3:
            if ( camera )
                inputState = !camera->isInputReceiverEnabled();
            break;
    }

    if ( camera )
    {
        camera->setInputReceiverEnabled ( inputState );
        Game->Device->getCursorControl()->setVisible( !inputState );
    }

    if ( gui.Window )
    {
        gui.Window->setVisible ( Game->guiActive != 0 );
    }

    if ( Game->guiActive &&
            gui.SceneTree && Game->Device->getGUIEnvironment()->getFocus() != gui.SceneTree
        )
    {
        gui.SceneTree->getRoot()->clearChildren();
        addSceneTreeItem ( Game->Device->getSceneManager()->getRootSceneNode(), gui.SceneTree->getRoot() );
    }

    Game->Device->getGUIEnvironment()->setFocus ( Game->guiActive ? gui.Window: 0 );
}

VIII. Interactions

Gère les interactions du joueur.

 
Sélectionnez
bool CQuake3EventHandler::OnEvent(const SEvent& eve)
{
    if ( eve.EventType == EET_LOG_TEXT_EVENT )
    {
        return false;
    }

    if ( Game->guiActive && eve.EventType == EET_GUI_EVENT )
    {
        if ( eve.GUIEvent.Caller == gui.MapList && eve.GUIEvent.EventType == gui::EGET_LISTBOX_SELECTED_AGAIN )
        {
            s32 selected = gui.MapList->getSelected();
            if ( selected >= 0 )
            {
                stringw loadMap = gui.MapList->getListItem ( selected );
                if ( 0 == MapParent || loadMap != Game->CurrentMapName )
                {
                    printf ( "Loading map %ls\n", loadMap.c_str() );
                    LoadMap ( loadMap , 1 );
                    if ( 0 == Game->loadParam.loadSkyShader )
                    {
                        AddSky ( 1, "skydome2" );
                    }
                    CreatePlayers ();
                    CreateGUI ();
                    SetGUIActive ( 0 );
                    return true;
                }
            }
        }
        else
        if ( eve.GUIEvent.Caller == gui.ArchiveRemove && eve.GUIEvent.EventType == gui::EGET_BUTTON_CLICKED )
        {
            Game->Device->getFileSystem()->removeFileArchive( gui.ArchiveList->getSelected() );
            Game->CurrentMapName = "";
            AddArchive ( "" );
        }
        else
        if ( eve.GUIEvent.Caller == gui.ArchiveAdd && eve.GUIEvent.EventType == gui::EGET_BUTTON_CLICKED )
        {
            if ( 0 == gui.ArchiveFileOpen )
            {
                Game->Device->getFileSystem()->setFileListSystem ( FILESYSTEM_NATIVE );
                gui.ArchiveFileOpen = Game->Device->getGUIEnvironment()->addFileOpenDialog ( L"Add Game Archive" , false,gui.Window  );
            }
        }
        else
        if ( eve.GUIEvent.Caller == gui.ArchiveFileOpen && eve.GUIEvent.EventType == gui::EGET_FILE_SELECTED )
        {
            AddArchive ( gui.ArchiveFileOpen->getFileName() );
            gui.ArchiveFileOpen = 0;
        }
        else
        if ( eve.GUIEvent.Caller == gui.ArchiveFileOpen && eve.GUIEvent.EventType == gui::EGET_DIRECTORY_SELECTED )
        {
            AddArchive ( gui.ArchiveFileOpen->getDirectoryName() );
        }
        else
        if ( eve.GUIEvent.Caller == gui.ArchiveFileOpen && eve.GUIEvent.EventType == gui::EGET_FILE_CHOOSE_DIALOG_CANCELLED )
        {
            gui.ArchiveFileOpen = 0;
        }
        else
        if ( ( eve.GUIEvent.Caller == gui.ArchiveUp || eve.GUIEvent.Caller == gui.ArchiveDown ) &&
            eve.GUIEvent.EventType == gui::EGET_BUTTON_CLICKED )
        {
            s32 rel = eve.GUIEvent.Caller == gui.ArchiveUp ? -1 : 1;
            if ( Game->Device->getFileSystem()->moveFileArchive ( gui.ArchiveList->getSelected (), rel ) )
            {
                s32 newIndex = core::s32_clamp ( gui.ArchiveList->getSelected() + rel, 0, gui.ArchiveList->getRowCount() - 1 );
                AddArchive ( "" );
                gui.ArchiveList->setSelected ( newIndex );
                Game->CurrentMapName = "";
            }
        }
        else
        if ( eve.GUIEvent.Caller == gui.VideoDriver && eve.GUIEvent.EventType == gui::EGET_COMBO_BOX_CHANGED )
        {
            Game->deviceParam.DriverType = (E_DRIVER_TYPE) gui.VideoDriver->getItemData ( gui.VideoDriver->getSelected() );
        }
        else
        if ( eve.GUIEvent.Caller == gui.VideoMode && eve.GUIEvent.EventType == gui::EGET_COMBO_BOX_CHANGED )
        {
            u32 val = gui.VideoMode->getItemData ( gui.VideoMode->getSelected() );
            Game->deviceParam.WindowSize.Width = val >> 16;
            Game->deviceParam.WindowSize.Height = val & 0xFFFF;
        }
        else
        if ( eve.GUIEvent.Caller == gui.FullScreen && eve.GUIEvent.EventType == gui::EGET_CHECKBOX_CHANGED )
        {
            Game->deviceParam.Fullscreen = gui.FullScreen->isChecked();
        }
        else
        if ( eve.GUIEvent.Caller == gui.Bit32 && eve.GUIEvent.EventType == gui::EGET_CHECKBOX_CHANGED )
        {
            Game->deviceParam.Bits = gui.Bit32->isChecked() ? 32 : 16;
        }
        else
        if ( eve.GUIEvent.Caller == gui.MultiSample && eve.GUIEvent.EventType == gui::EGET_SCROLL_BAR_CHANGED )
        {
            Game->deviceParam.AntiAlias = gui.MultiSample->getPos();
        }
        else
        if ( eve.GUIEvent.Caller == gui.Tesselation && eve.GUIEvent.EventType == gui::EGET_SCROLL_BAR_CHANGED )
        {
            Game->loadParam.patchTesselation = gui.Tesselation->getPos ();
        }
        else
        if ( eve.GUIEvent.Caller == gui.Gamma && eve.GUIEvent.EventType == gui::EGET_SCROLL_BAR_CHANGED )
        {
            Game->GammaValue = gui.Gamma->getPos () * 0.01f;
            Game->Device->setGammaRamp ( Game->GammaValue, Game->GammaValue, Game->GammaValue, 0.f, 0.f );
        }
        else
        if ( eve.GUIEvent.Caller == gui.SetVideoMode && eve.GUIEvent.EventType == gui::EGET_BUTTON_CLICKED )
        {
            Game->retVal = 2;
            Game->Device->closeDevice();
        }
        else
        if ( eve.GUIEvent.Caller == gui.Window && eve.GUIEvent.EventType == gui::EGET_ELEMENT_CLOSED )
        {
            Game->Device->closeDevice();
        }
        else
        if ( eve.GUIEvent.Caller == gui.Collision && eve.GUIEvent.EventType == gui::EGET_CHECKBOX_CHANGED )
        {
            // Active le vol.
            Game->flyTroughState ^= 1;
            Player[0].cam()->setAnimateTarget ( Game->flyTroughState == 0 );

            printf ( "collision %d\n", Game->flyTroughState == 0 );
        }
        else
        if ( eve.GUIEvent.Caller == gui.Visible_Map && eve.GUIEvent.EventType == gui::EGET_CHECKBOX_CHANGED )
        {
            bool v = gui.Visible_Map->isChecked();

            if ( MapParent )
            {
                printf ( "static node set visible %d\n",v );
                MapParent->setVisible ( v );
            }
        }
        else
        if ( eve.GUIEvent.Caller == gui.Visible_Shader && eve.GUIEvent.EventType == gui::EGET_CHECKBOX_CHANGED )
        {
            bool v = gui.Visible_Shader->isChecked();

            if ( ShaderParent )
            {
                printf ( "shader node set visible %d\n",v );
                ShaderParent->setVisible ( v );
            }
        }
        else
        if ( eve.GUIEvent.Caller == gui.Visible_Skydome && eve.GUIEvent.EventType == gui::EGET_CHECKBOX_CHANGED )
        {
            if ( SkyNode )
            {
                bool v = !SkyNode->isVisible();
                printf ( "skynode set visible %d\n",v );
                SkyNode->setVisible ( v );
            }
        }
        else
        if ( eve.GUIEvent.Caller == gui.Respawn && eve.GUIEvent.EventType == gui::EGET_BUTTON_CLICKED )
        {
            Player[0].respawn ();
        }

        return false;
    }

    // Feux
    if ((eve.EventType == EET_KEY_INPUT_EVENT && eve.KeyInput.Key == KEY_SPACE &&
        eve.KeyInput.PressedDown == false) ||
        (eve.EventType == EET_MOUSE_INPUT_EVENT && eve.MouseInput.Event == EMIE_LMOUSE_LEFT_UP)
        )
    {
        ICameraSceneNode * camera = Game->Device->getSceneManager()->getActiveCamera ();
        if ( camera && camera->isInputReceiverEnabled () )
        {
            useItem( Player + 0 );
        }
    }

    // Active l'interface utilisateur.
    if ((eve.EventType == EET_KEY_INPUT_EVENT && eve.KeyInput.Key == KEY_F1 &&
        eve.KeyInput.PressedDown == false) ||
        (eve.EventType == EET_MOUSE_INPUT_EVENT && eve.MouseInput.Event == EMIE_RMOUSE_LEFT_UP)
        )
    {
        SetGUIActive ( 2 );
    }

    // Vérifie si l'utilisateur presse une touche.
    if ( eve.EventType == EET_KEY_INPUT_EVENT && eve.KeyInput.PressedDown == false)
    {
        // Échap alterne la caméra d'entrée.
        if ( eve.KeyInput.Key == irr::KEY_ESCAPE )
        {
            SetGUIActive ( 3 );
        }
        else
        if (eve.KeyInput.Key == KEY_F11)
        {
            // Les captures d'écran sont effectuées sans gamma !
            IImage* image = Game->Device->getVideoDriver()->createScreenShot();
            if (image)
            {
                core::vector3df pos;
                core::vector3df rot;
                ICameraSceneNode * cam = Game->Device->getSceneManager()->getActiveCamera ();
                if ( cam )
                {
                    pos = cam->getPosition ();
                    rot = cam->getRotation ();
                }

                static const c8 *dName[] = { "null", "software", "burning",
                    "d3d8", "d3d9", "opengl" };

                snprintf(buf, 256, "%s_%ls_%.0f_%.0f_%.0f_%.0f_%.0f_%.0f.jpg",
                        dName[Game->Device->getVideoDriver()->getDriverType()],
                        Game->CurrentMapName.c_str(),
                        pos.X, pos.Y, pos.Z,
                        rot.X, rot.Y, rot.Z
                        );
                path filename ( buf );
                filename.replace ( '/', '_' );
                printf ( "screenshot : %s\n", filename.c_str() );
                Game->Device->getVideoDriver()->writeImageToFile(image, filename, 100 );
                image->drop();
            }
        }
        else
        if (eve.KeyInput.Key == KEY_F9)
        {
            s32 value = EDS_OFF;

            Game->debugState = ( Game->debugState + 1 ) & 3;

            switch ( Game->debugState )
            {
                case 1: value = EDS_NORMALS | EDS_MESH_WIRE_OVERLAY | EDS_BBOX_ALL; break;
                case 2: value = EDS_NORMALS | EDS_MESH_WIRE_OVERLAY | EDS_SKELETON; break;
            }
set debug map data on/off debugState = debugState == EDS_OFF ? EDS_NORMALS | EDS_MESH_WIRE_OVERLAY | EDS_BBOX_ALL: EDS_OFF; 
            if ( ItemParent )
            {
                list<ISceneNode*>::ConstIterator it = ItemParent->getChildren().begin();
                for (; it != ItemParent->getChildren().end(); ++it)
                {
                    (*it)->setDebugDataVisible ( value );
                }
            }

            if ( ShaderParent )
            {
                list<ISceneNode*>::ConstIterator it = ShaderParent->getChildren().begin();
                for (; it != ShaderParent->getChildren().end(); ++it)
                {
                    (*it)->setDebugDataVisible ( value );
                }
            }

            if ( UnresolvedParent )
            {
                list<ISceneNode*>::ConstIterator it = UnresolvedParent->getChildren().begin();
                for (; it != UnresolvedParent->getChildren().end(); ++it)
                {
                    (*it)->setDebugDataVisible ( value );
                }
            }

            if ( FogParent )
            {
                list<ISceneNode*>::ConstIterator it = FogParent->getChildren().begin();
                for (; it != FogParent->getChildren().end(); ++it)
                {
                    (*it)->setDebugDataVisible ( value );
                }
            }

            if ( SkyNode )
            {
                SkyNode->setDebugDataVisible ( value );
            }

        }
        else
        if (eve.KeyInput.Key == KEY_F8)
        {
            // Active/désactive la gravité.
            Game->gravityState ^= 1;
            Player[0].cam()->setGravity ( getGravity ( Game->gravityState ? "earth" : "none" ) );
            printf ( "gravity %s\n", Game->gravityState ? "earth" : "none" );
        }
        else
        if (eve.KeyInput.Key == KEY_F7)
        {
            // Active le vol.
            Game->flyTroughState ^= 1;
            Player[0].cam()->setAnimateTarget ( Game->flyTroughState == 0 );
            if ( gui.Collision )
                gui.Collision->setChecked ( Game->flyTroughState == 0 );

            printf ( "collision %d\n", Game->flyTroughState == 0 );
        }
        else
        if (eve.KeyInput.Key == KEY_F2)
        {
            Player[0].respawn ();
        }
        else
        if (eve.KeyInput.Key == KEY_F3)
        {
            if ( MapParent )
            {
                bool v = !MapParent->isVisible ();
                printf ( "static node set visible %d\n",v );
                MapParent->setVisible ( v );
                if ( gui.Visible_Map )
                    gui.Visible_Map->setChecked ( v );
            }
        }
        else
        if (eve.KeyInput.Key == KEY_F4)
        {
            if ( ShaderParent )
            {
                bool v = !ShaderParent->isVisible ();
                printf ( "shader node set visible %d\n",v );
                ShaderParent->setVisible ( v );
                if ( gui.Visible_Shader )
                    gui.Visible_Shader->setChecked ( v );
            }
        }
        else
        if (eve.KeyInput.Key == KEY_F5)
        {
            if ( FogParent )
            {
                bool v = !FogParent->isVisible ();
                printf ( "fog node set visible %d\n",v );
                FogParent->setVisible ( v );
                if ( gui.Visible_Fog )
                    gui.Visible_Fog->setChecked ( v );
            }

        }
        else
        if (eve.KeyInput.Key == KEY_F6)
        {
            if ( UnresolvedParent )
            {
                bool v = !UnresolvedParent->isVisible ();
                printf ( "unresolved node set visible %d\n",v );
                UnresolvedParent->setVisible ( v );
                if ( gui.Visible_Unresolved )
                    gui.Visible_Unresolved->setChecked ( v );
            }
        }
    }

    // Vérifie si l'utilisateur presse la touche C (pour s'accroupir).
    if ( eve.EventType == EET_KEY_INPUT_EVENT && eve.KeyInput.Key == KEY_KEY_C )
    {
        // s'accroupir
        ISceneNodeAnimatorCollisionResponse *anim = Player[0].cam ();
        if ( anim && 0 == Game->flyTroughState )
        {
            if ( false == eve.KeyInput.PressedDown )
            {
                // se lève
                anim->setEllipsoidRadius (  vector3df(30,45,30) );
                anim->setEllipsoidTranslation ( vector3df(0,40,0));

            }
            else
            {
                // sur vos genoux.
                anim->setEllipsoidRadius (  vector3df(30,20,30) );
                anim->setEllipsoidTranslation ( vector3df(0,20,0));
            }
            return true;
        }
    }
    return false;
}

IX. Objets

Utilisation d'objet.

 
Sélectionnez
void CQuake3EventHandler::useItem( Q3Player * player)
{
    ISceneManager* smgr = Game->Device->getSceneManager();
    ICameraSceneNode* camera = smgr->getActiveCamera();

    if (!camera)
        return;

    SParticleImpact imp;
    imp.when = 0;

    // Obtient la ligne de la caméra.

    vector3df start = camera->getPosition();

    if ( player->WeaponNode )
    {
        start.X += 0.f;
        start.Y += 0.f;
        start.Z += 0.f;
    }

    vector3df end = (camera->getTarget() - start);
    end.normalize();
    start += end*20.0f;

    end = start + (end * camera->getFarValue());

    triangle3df triangle;
    line3d<f32> line(start, end);

    // Obtient le point d'intersection avec la carte.
    scene::ISceneNode* hitNode;
    if (smgr->getSceneCollisionManager()->getCollisionPoint(
        line, Meta, end, triangle,hitNode))
    {
        // Collisions avec les murs.
        vector3df out = triangle.getNormal();
        out.setLength(0.03f);

        imp.when = 1;
        imp.outVector = out;
        imp.pos = end;

        player->setAnim ( "pow" );
        player->Anim[1].next += player->Anim[1].delta;
    }
    else
    {
        // Pas de collision avec les murs.
        vector3df start = camera->getPosition();
        if ( player->WeaponNode )
        {
            //start.X += 10.f;
            //start.Y += -5.f;
            //start.Z += 1.f;
        }

        vector3df end = (camera->getTarget() - start);
        end.normalize();
        start += end*20.0f;
        end = start + (end * camera->getFarValue());
    }

    // Crée une boule de feu.
    ISceneNode* node = 0;
    node = smgr->addBillboardSceneNode( BulletParent,dimension2d<f32>(10,10), start);

    node->setMaterialFlag(EMF_LIGHTING, false);
    node->setMaterialTexture(0, Game->Device->getVideoDriver()->getTexture("fireball.bmp"));
    node->setMaterialFlag(video::EMF_ZWRITE_ENABLE, false);
    node->setMaterialType(EMT_TRANSPARENT_ADD_COLOR);

    f32 length = (f32)(end - start).getLength();
    const f32 speed = 5.8f;
    u32 time = (u32)(length / speed);

    ISceneNodeAnimator* anim = 0;

    // Met la ligne de vol.

    anim = smgr->createFlyStraightAnimator(start, end, time);
    node->addAnimator(anim);
    anim->drop();

    snprintf ( buf, 64, "bullet: %s on %.1f,%1.f,%1.f",
                imp.when ? "hit" : "nohit", end.X, end.Y, end.Z );
    node->setName ( buf );


    anim = smgr->createDeleteAnimator(time);
    node->addAnimator(anim);
    anim->drop();

    if (imp.when)
    {
        // Crée une note d'impact.
        imp.when = Game->Device->getTimer()->getTime() +
            (time + (s32) ( ( 1.f + Noiser::get() ) * 250.f ));
        Impacts.push_back(imp);
    }

    // Joue le son
}

// dessiné quand les boules touchent quelque chose.
void CQuake3EventHandler::createParticleImpacts( u32 now )
{
    ISceneManager* sm = Game->Device->getSceneManager();

    struct smokeLayer
    {
        const c8 * texture;
        f32 scale;
        f32 minparticleSize;
        f32 maxparticleSize;
        f32 boxSize;
        u32 minParticle;
        u32 maxParticle;
        u32 fadeout;
        u32 lifetime;
    };

    smokeLayer smoke[] =
    {
        { "smoke2.jpg", 0.4f, 1.5f, 18.f, 20.f, 20, 50, 2000, 10000 },
        { "smoke3.jpg", 0.2f, 1.2f, 15.f, 20.f, 10, 30, 1000, 12000 }
    };


    u32 i;
    u32 g;
    s32 factor = 1;
    for ( g = 0; g != 2; ++g )
    {
        smoke[g].minParticle *= factor;
        smoke[g].maxParticle *= factor;
        smoke[g].lifetime *= factor;
        smoke[g].boxSize *= Noiser::get() * 0.5f;
    }

    for ( i=0; i < Impacts.size(); ++i)
    {
        if (now < Impacts[i].when)
            continue;

        // Crée un système de particules de fumée.
        IParticleSystemSceneNode* pas = 0;

        for ( g = 0; g != 2; ++g )
        {
            pas = sm->addParticleSystemSceneNode(false, BulletParent, -1, Impacts[i].pos);

            snprintf ( buf, 64, "bullet impact smoke at %.1f,%.1f,%1.f",
                Impacts[i].pos.X,Impacts[i].pos.Y,Impacts[i].pos.Z);
            pas->setName ( buf );

            // Crée un nuage plat.
            vector3df direction = Impacts[i].outVector;
            direction *= smoke[g].scale;
            IParticleEmitter* em = pas->createBoxEmitter(
                aabbox3d<f32>(-4.f,0.f,-4.f,20.f,smoke[g].minparticleSize,20.f),
                direction,smoke[g].minParticle, smoke[g].maxParticle,
                video::SColor(0,0,0,0),video::SColor(0,128,128,128),
                250,4000, 60);

            em->setMinStartSize (dimension2d<f32>( smoke[g].minparticleSize, smoke[g].minparticleSize));
            em->setMaxStartSize (dimension2d<f32>( smoke[g].maxparticleSize, smoke[g].maxparticleSize));

            pas->setEmitter(em);
            em->drop();

            // Les particules deviennent invisibles.
            IParticleAffector* paf = pas->createFadeOutParticleAffector(
                video::SColor ( 0, 0, 0, 0 ), smoke[g].fadeout);
            pas->addAffector(paf);
            paf->drop();

            // Temps de vie du système de particules.
            ISceneNodeAnimator* anim = sm->createDeleteAnimator( smoke[g].lifetime);
            pas->addAnimator(anim);
            anim->drop();

            pas->setMaterialFlag(video::EMF_LIGHTING, false);
            pas->setMaterialFlag(video::EMF_ZWRITE_ENABLE, false);
            pas->setMaterialType(video::EMT_TRANSPARENT_ADD_COLOR );
            pas->setMaterialTexture(0, Game->Device->getVideoDriver()->getTexture( smoke[g].texture ));
        }


        // Joue le son d'impact.
        #ifdef USE_IRRKLANG
if (irrKlang) { audio::ISound* sound = irrKlang->play3D(impactSound, Impacts[i].pos, false, false, true);
if (sound) { adjust max value a bit to make to sound of an impact louder sound->setMinDistance(400); sound->drop(); } } 
        #endif


        // Supprime l'entrée.
        Impacts.erase(i);
        i--;
    }
}

X. Rendu

Système de rendu.

 
Sélectionnez
void CQuake3EventHandler::Render()
{
    IVideoDriver * driver = Game->Device->getVideoDriver();
    if ( 0 == driver )
        return;

    // TODO: Ceci ne fonctionne pas pour le moment.
    const bool anaglyph=false;
    if (anaglyph)
    {
        scene::ICameraSceneNode* cameraOld = Game->Device->getSceneManager()->getActiveCamera();
        driver->beginScene(true, true, SColor(0,0,0,0));
        driver->getOverrideMaterial().Material.ColorMask = ECP_NONE;
        driver->getOverrideMaterial().EnableFlags  = EMF_COLOR_MASK;
        driver->getOverrideMaterial().EnablePasses = ESNRP_SKY_BOX +
                                                     ESNRP_SOLID +
                                                     ESNRP_TRANSPARENT +
                                                     ESNRP_TRANSPARENT_EFFECT +
                                                     ESNRP_SHADOW;
        Game->Device->getSceneManager()->drawAll();
        driver->clearZBuffer();

        const vector3df oldPosition = cameraOld->getPosition();
        const vector3df oldTarget   = cameraOld->getTarget();
        const matrix4 startMatrix   = cameraOld->getAbsoluteTransformation();
        const vector3df focusPoint  = (oldTarget -
                cameraOld->getAbsolutePosition()).setLength(10000) +
                cameraOld->getAbsolutePosition() ;

        scene::ICameraSceneNode* camera = cameraOld;//Game->Device->getSceneManager()->addCameraSceneNode();

        // Oeil gauche...
        vector3df pos;
        matrix4   move;

        move.setTranslation( vector3df(-1.5f,0.0f,0.0f) );
        pos=(startMatrix*move).getTranslation();

        driver->getOverrideMaterial().Material.ColorMask = ECP_RED;
        driver->getOverrideMaterial().EnableFlags  = EMF_COLOR_MASK;
        driver->getOverrideMaterial().EnablePasses =
                ESNRP_SKY_BOX|ESNRP_SOLID|ESNRP_TRANSPARENT|
                ESNRP_TRANSPARENT_EFFECT|ESNRP_SHADOW;

        camera->setPosition(pos);
        camera->setTarget(focusPoint);

        Game->Device->getSceneManager()->drawAll();
        driver->clearZBuffer();

        // Oeil droit...
        move.setTranslation( vector3df(1.5f,0.0f,0.0f) );
        pos=(startMatrix*move).getTranslation();

        driver->getOverrideMaterial().Material.ColorMask = ECP_GREEN + ECP_BLUE;
        driver->getOverrideMaterial().EnableFlags  = EMF_COLOR_MASK;
        driver->getOverrideMaterial().EnablePasses =
                ESNRP_SKY_BOX|ESNRP_SOLID|ESNRP_TRANSPARENT|
                ESNRP_TRANSPARENT_EFFECT|ESNRP_SHADOW;

        camera->setPosition(pos);
        camera->setTarget(focusPoint);

        Game->Device->getSceneManager()->drawAll();

        driver->getOverrideMaterial().Material.ColorMask=ECP_ALL;
        driver->getOverrideMaterial().EnableFlags=0;
        driver->getOverrideMaterial().EnablePasses=0;

        if (camera != cameraOld)
        {
            Game->Device->getSceneManager()->setActiveCamera(cameraOld);
            camera->remove();
        }
        else
        {
            camera->setPosition(oldPosition);
            camera->setTarget(oldTarget);
        }
    }
    else
    {
        driver->beginScene(true, true, SColor(0,0,0,0));
        Game->Device->getSceneManager()->drawAll();
    }
    Game->Device->getGUIEnvironment()->drawAll();
    driver->endScene();
}

Met à jour le nœud de scène générique.

 
Sélectionnez
void CQuake3EventHandler::Animate()
{
    u32 now = Game->Device->getTimer()->getTime();

    Q3Player * player = Player + 0;

    checkTimeFire ( player->Anim, 4, now );

    // Demande les attributs du gestionnaire de scène.
    if ( player->Anim[0].flags & FIRED )
    {
        ISceneManager *smgr = Game->Device->getSceneManager ();
        wchar_t msg[128];
        IVideoDriver * driver = Game->Device->getVideoDriver();

        IAttributes * attr = smgr->getParameters();
        swprintf ( msg, 128,
            L"Q3 %s [%ls], FPS:%03d Tri:%.03fm Cull %d/%d nodes (%d,%d,%d)",
            Game->CurrentMapName.c_str(),
            driver->getName(),
            driver->getFPS (),
            (f32) driver->getPrimitiveCountDrawn( 0 ) * ( 1.f / 1000000.f ),
            attr->getAttributeAsInt ( "culled" ),
            attr->getAttributeAsInt ( "calls" ),
            attr->getAttributeAsInt ( "drawn_solid" ),
            attr->getAttributeAsInt ( "drawn_transparent" ),
            attr->getAttributeAsInt ( "drawn_transparent_effect" )
            );
        Game->Device->setWindowCaption( msg );

        swprintf ( msg, 128,
                    L"%03d fps, F1 GUI on/off, F2 respawn, F3-F6 toggle Nodes, F7 Collision on/off"
                    L", F8 Gravity on/off, Right Mouse Toggle GUI",
                    Game->Device->getVideoDriver()->getFPS ()
                );
        if ( gui.StatusLine )
            gui.StatusLine->setText ( msg );
        player->Anim[0].flags &= ~FIRED;
    }

    // à l'arrêt&#8230; 
    if ( player->Anim[1].flags & FIRED )
    {
        if ( strcmp ( player->animation, "idle" ) )
            player->setAnim ( "idle" );

        player->Anim[1].flags &= ~FIRED;
    }

    createParticleImpacts ( now );

}

XI. Boucle principale

Boucle principale du jeu.

 
Sélectionnez
void runGame ( GameData *game )
{
    if ( game->retVal >= 3 )
        return;

    game->Device = (*game->createExDevice) ( game->deviceParam );
    if ( 0 == game->Device)
    {
        // Ne peut pas créer le pilote sélectionné.
        game->retVal = 0;
        return;
    }

    // Crée un receveur d'événements basé sur les données du jeu.
    CQuake3EventHandler *eventHandler = new CQuake3EventHandler( game );

    // Charge les configurations stockées.
    game->load ( "explorer.cfg" );

    // Ajoute nos propres dossiers des médias et des archives au système de fichiers.
    for ( u32 i = 0; i < game->CurrentArchiveList.size(); ++i )
    {
        eventHandler->AddArchive ( game->CurrentArchiveList[i] );
    }

    // Charge une carte ou démarre l'interface utilisateur.
    if ( game->CurrentMapName.size () )
    {
        eventHandler->LoadMap ( game->CurrentMapName, 1 );
        if ( 0 == game->loadParam.loadSkyShader )
            eventHandler->AddSky ( 1, "skydome2" );
        eventHandler->CreatePlayers ();
        eventHandler->CreateGUI ();
        eventHandler->SetGUIActive ( 0 );

        // Met le joueur à la dernière position lors du redémarrage.
        if ( game->retVal == 2 )
        {
            eventHandler->GetPlayer( 0 )->setpos ( game->PlayerPosition, game->PlayerRotation );
        }
    }
    else
    {
        // Démarrage vide.
        eventHandler->AddSky ( 1, "skydome2" );
        eventHandler->CreatePlayers ();
        eventHandler->CreateGUI ();
        eventHandler->SetGUIActive ( 1 );
        background_music ( "IrrlichtTheme.ogg" );
    }


    game->retVal = 3;
    while( game->Device->run() )
    {
        eventHandler->Animate ();
        eventHandler->Render ();
        //if ( !game->Device->isWindowActive() )
            game->Device->yield();
    }

    game->Device->setGammaRamp ( 1.f, 1.f, 1.f, 0.f, 0.f );
    delete eventHandler;
}

#if defined (_IRR_WINDOWS_) && 0
    #pragma comment(linker, "/subsystem:windows /ENTRY:mainCRTStartup")
#endif

La fonction main, fait toutes les initialisations.

 
Sélectionnez
int IRRCALLCONV main(int argc, char* argv[])
{
    path prgname(argv[0]);
    GameData game ( deletePathFromPath ( prgname, 1 ) );

    // Charge dynamiquement Irrlicht.
    const c8 * dllName = argc > 1 ? argv[1] : "irrlicht.dll";
    game.createExDevice = load_createDeviceEx ( dllName );
    if ( 0 == game.createExDevice )
    {
        game.retVal = 3;
        printf ( "Could not load %s.\n", dllName );
        return game.retVal; // Ne peut pas charger le dll.
    }

    // Commence sans demander le pilote.
    game.retVal = 1;
    do
    {
        // Si le pilote ne peut pas être créé, demande un autre pilote.
        if ( game.retVal == 0 )
        {
            game.setDefault ();
            // demande à l'utilisateur un pilote.
            game.deviceParam.DriverType=driverChoiceConsole();
            if (game.deviceParam.DriverType==video::EDT_COUNT)
                game.retVal = 3;
        }
        runGame ( &game );
    } while ( game.retVal < 3 );

    return game.retVal;
}

XII. Conclusion

Vous pouvez désormais créer votre propre chargeur de cartes en vous inspirant de celui-ci.

Dans le prochain tutoriel Visualiseur de matériels, nous verrons comment jouer avec les paramètres des matériels et nous observerons les résultats.

XIII. Remerciements

Merci à Nikolaus Gebhardt de nous permettre de traduire ce tutoriel.

Merci à LittleWhite pour sa relecture technique ainsi qu'à ClaudeLELOUP pour sa relecture orthographique.

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

  

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2013 Neckara. Aucune reproduction, même partielle, ne peut être faite de ce site ni de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.