I. Configuration▲
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 : https://www.moddb.com/games/quake-iii-arena/downloads/quake-3-demo
Copyright 2006-2011 Burningwater, Thomas Alten.
#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.
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.
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.
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.
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
\n
playerrotation %.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.
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.
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.
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.0
f, 0.6
f, -
1
, keyMap, 10
, false
, 0.6
f);
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.0005
f
);
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".
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.
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.
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.
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.
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.
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.
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.3333333333
f ) ) a =
"4:3"
;
else
if
( core::
equals ( aspect, 1.6666666
f ) ) a =
"15:9 widescreen"
;
else
if
( core::
equals ( aspect, 1.7777777
f ) ) a =
"16:9 widescreen"
;
else
if
( core::
equals ( aspect, 1.6
f ) ) a =
"16:10 widescreen"
;
else
if
( core::
equals ( aspect, 2.133333
f ) ) 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 ).
\n
Press 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.
\n
Press 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.
\n
Press 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.
\n
Press 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.
\n
Press 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.
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.
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.
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.
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 ?
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.
Q3ModelFactory ( Game->
loadParam, Game->
Device, Mesh, ItemParent, false
);
}
Ajoute un nœud de scène avec une icône à l'arbre de scène.
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.95
f, 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.
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.01
f;
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.
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.0
f;
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.03
f);
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.0
f;
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.8
f;
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.4
f, 1.5
f, 18.
f, 20.
f, 20
, 50
, 2000
, 10000
}
,
{
"smoke3.jpg"
, 0.2
f, 1.2
f, 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.5
f;
}
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.
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.5
f,0.0
f,0.0
f) );
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.5
f,0.0
f,0.0
f) );
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.
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…
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.
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.
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.