I. Prérequis▲
Vous avez deux nœuds pour rendre plus facilement visibles les différences entre deux configurations. De plus, vous avez un lightscenenode et vous pouvez modifier les valeurs de l'ambiance globale.
#include
<irrlicht.h>
#include
"driverChoice.h"
using
namespace
irr;
#ifdef _MSC_VER
#pragma comment(lib,
"Irrlicht.lib"
)
#endif
Les variables à l'intérieur de cet espace de nom anonyme sont globales et sont restreintes à ce fichier.
namespace
{
const
wchar_t
*
const
DriverTypeNames[] =
{
L"NULL"
,
L"SOFTWARE"
,
L"BURNINGSVIDEO"
,
L"DIRECT3D8"
,
L"DIRECT3D9"
,
L"OPENGL"
,
0
,
}
;
// Pour les identifiants d'interface utilisateur.
enum
EGUI_IDS
{
GUI_ID_OPEN_TEXTURE =
1
,
GUI_ID_QUIT,
GUI_ID_MAX
}
;
// Nom utilisé dans la sélection de texture pour effacer les textures dans un nœud.
const
core::
stringw CLEAR_TEXTURE =
L"CLEAR texture"
;
// Quelques constantes de couleur utiles.
const
video::
SColor SCOL_BLACK =
video::
SColor(255
, 0
, 0
, 0
);
const
video::
SColor SCOL_BLUE =
video::
SColor(255
, 0
, 0
, 255
);
const
video::
SColor SCOL_CYAN =
video::
SColor(255
, 0
, 255
, 255
);
const
video::
SColor SCOL_GRAY =
video::
SColor(255
, 128
,128
, 128
);
const
video::
SColor SCOL_GREEN =
video::
SColor(255
, 0
, 255
, 0
);
const
video::
SColor SCOL_MAGENTA =
video::
SColor(255
, 255
, 0
, 255
);
const
video::
SColor SCOL_RED =
video::
SColor(255
, 255
, 0
, 0
);
const
video::
SColor SCOL_YELLOW =
video::
SColor(255
, 255
, 255
, 0
);
const
video::
SColor SCOL_WHITE =
video::
SColor(255
, 255
, 255
, 255
);
}
; // namespace
Retourne un nouveau nombre unique à chaque appel.
s32 makeUniqueId()
{
static
int
unique =
GUI_ID_MAX;
++
unique;
return
unique;
}
Recherche quel type de vertex est nécessaire pour le type de matériel donné.
video::
E_VERTEX_TYPE getVertexTypeForMaterialType(video::
E_MATERIAL_TYPE materialType)
{
using
namespace
video;
switch
( materialType )
{
case
EMT_SOLID:
return
EVT_STANDARD;
case
EMT_SOLID_2_LAYER:
return
EVT_STANDARD;
case
EMT_LIGHTMAP:
case
EMT_LIGHTMAP_ADD:
case
EMT_LIGHTMAP_M2:
case
EMT_LIGHTMAP_M4:
case
EMT_LIGHTMAP_LIGHTING:
case
EMT_LIGHTMAP_LIGHTING_M2:
case
EMT_LIGHTMAP_LIGHTING_M4:
return
EVT_2TCOORDS;
case
EMT_DETAIL_MAP:
return
EVT_2TCOORDS;
case
EMT_SPHERE_MAP:
return
EVT_STANDARD;
case
EMT_REFLECTION_2_LAYER:
return
EVT_2TCOORDS;
case
EMT_TRANSPARENT_ADD_COLOR:
return
EVT_STANDARD;
case
EMT_TRANSPARENT_ALPHA_CHANNEL:
return
EVT_STANDARD;
case
EMT_TRANSPARENT_ALPHA_CHANNEL_REF:
return
EVT_STANDARD;
case
EMT_TRANSPARENT_VERTEX_ALPHA:
return
EVT_STANDARD;
case
EMT_TRANSPARENT_REFLECTION_2_LAYER:
return
EVT_2TCOORDS;
case
EMT_NORMAL_MAP_SOLID:
case
EMT_NORMAL_MAP_TRANSPARENT_ADD_COLOR:
case
EMT_NORMAL_MAP_TRANSPARENT_VERTEX_ALPHA:
case
EMT_PARALLAX_MAP_SOLID:
case
EMT_PARALLAX_MAP_TRANSPARENT_ADD_COLOR:
case
EMT_PARALLAX_MAP_TRANSPARENT_VERTEX_ALPHA:
return
EVT_TANGENTS;
case
EMT_ONETEXTURE_BLEND:
return
EVT_STANDARD;
case
EMT_FORCE_32BIT:
return
EVT_STANDARD;
}
return
EVT_STANDARD;
}
II. Contrôleur d'interface▲
Un contrôleur d'interface utilisateur personnalisé pour éditer les valeurs des couleurs.
class
CColorControl : public
gui::
IGUIElement
{
public
:
// Constructeur.
CColorControl(gui::
IGUIEnvironment*
guiEnv, const
core::
position2d<
s32>
&
pos, const
wchar_t
*
text, IGUIElement*
parent, s32 id=-
1
)
:
gui::
IGUIElement(gui::
EGUIET_ELEMENT, guiEnv, parent,id, core::
rect<
s32 >
(pos, pos+
core::
dimension2d<
s32>
(80
, 75
)))
, DirtyFlag(true
)
, ColorStatic(0
)
, EditAlpha(0
)
, EditRed(0
)
, EditGreen(0
)
, EditBlue(0
)
{
using
namespace
gui;
ButtonSetId =
makeUniqueId();
const
core::
rect<
s32 >
rectControls(0
,0
,AbsoluteRect.getWidth(),AbsoluteRect.getHeight() );
IGUIStaticText *
groupElement =
guiEnv->
addStaticText (L""
, rectControls, true
, false
, this
, -
1
, false
);
groupElement->
setNotClipped(true
);
guiEnv->
addStaticText (text, core::
rect<
s32>
(0
,0
,80
,15
), false
, false
, groupElement, -
1
, false
);
EditAlpha =
addEditForNumbers(guiEnv, core::
position2d<
s32>
(0
,15
), L"a"
, -
1
, groupElement );
EditRed =
addEditForNumbers(guiEnv, core::
position2d<
s32>
(0
,30
), L"r"
, -
1
, groupElement );
EditGreen =
addEditForNumbers(guiEnv, core::
position2d<
s32>
(0
,45
), L"g"
, -
1
, groupElement );
EditBlue =
addEditForNumbers(guiEnv, core::
position2d<
s32>
(0
,60
), L"b"
, -
1
, groupElement );
ColorStatic =
guiEnv->
addStaticText (L""
, core::
rect<
s32>
(60
,15
,80
,75
), true
, false
, groupElement, -
1
, true
);
guiEnv->
addButton (core::
rect<
s32>
(60
,35
,80
,50
), groupElement, ButtonSetId, L"set"
);
SetEditsFromColor(Color);
}
// Receveur d'événements.
virtual
bool
OnEvent(const
SEvent &
event)
{
if
( event.EventType !=
EET_GUI_EVENT )
return
false
;
if
( event.GUIEvent.Caller->
getID() ==
ButtonSetId &&
event.GUIEvent.EventType ==
gui::
EGET_BUTTON_CLICKED )
{
Color =
GetColorFromEdits();
SetEditsFromColor(Color);
}
return
false
;
}
// Change les valeurs de la couleur.
void
setColor(const
video::
SColor&
col)
{
DirtyFlag =
true
;
Color =
col;
SetEditsFromColor(Color);
}
// Donne les valeurs de la couleur.
const
video::
SColor&
getColor() const
{
return
Color;
}
// Réinitialise le fanion sale.
void
resetDirty()
{
DirtyFlag =
false
;
}
// Quand la couleur a été changée, le fanion sale est posé.
bool
isDirty() const
{
return
DirtyFlag;
}
;
protected
:
// Ajoute une boîte statique pour une description et une zone de texte ainsi les utilisateurs peuvent entrer des nombres.
gui::
IGUIEditBox*
addEditForNumbers(gui::
IGUIEnvironment*
guiEnv, const
core::
position2d<
s32>
&
pos, const
wchar_t
*
text, s32 id, gui::
IGUIElement *
parent)
{
using
namespace
gui;
core::
rect<
s32 >
rect(pos, pos+
core::
dimension2d<
s32>
(10
, 15
));
guiEnv->
addStaticText (text, rect, false
, false
, parent, -
1
, false
);
rect +=
core::
position2d<
s32>
( 20
, 0
);
rect.LowerRightCorner.X +=
20
;
gui::
IGUIEditBox*
edit =
guiEnv->
addEditBox(L"0"
, rect, true
, parent, id);
return
edit;
}
// Donne la valeur de la couleur à partir des champs d'édition.
video::
SColor GetColorFromEdits()
{
video::
SColor col;
if
(EditAlpha)
{
u32 alpha =
core::
strtoul10(core::
stringc(EditAlpha->
getText()).c_str());
if
(alpha >
255
)
alpha =
255
;
col.setAlpha(alpha);
}
if
(EditRed)
{
u32 red =
core::
strtoul10(core::
stringc(EditRed->
getText()).c_str());
if
(red >
255
)
red =
255
;
col.setRed(red);
}
if
(EditGreen)
{
u32 green =
core::
strtoul10(core::
stringc(EditGreen->
getText()).c_str());
if
(green >
255
)
green =
255
;
col.setGreen(green);
}
if
(EditBlue)
{
u32 blue =
core::
strtoul10(core::
stringc(EditBlue->
getText()).c_str());
if
(blue >
255
)
blue =
255
;
col.setBlue(blue);
}
return
col;
}
// Remplit les champs d'édition avec les valeurs de la couleur donnée.
void
SetEditsFromColor(video::
SColor col)
{
DirtyFlag =
true
;
if
( EditAlpha )
EditAlpha->
setText( core::
stringw(col.getAlpha()).c_str() );
if
( EditRed )
EditRed->
setText( core::
stringw(col.getRed()).c_str() );
if
( EditGreen )
EditGreen->
setText( core::
stringw(col.getGreen()).c_str() );
if
( EditBlue )
EditBlue->
setText( core::
stringw(col.getBlue()).c_str() );
if
( ColorStatic )
ColorStatic->
setBackgroundColor(col);
}
private
:
bool
DirtyFlag;
video::
SColor Color;
s32 ButtonSetId;
gui::
IGUIStaticText *
ColorStatic;
gui::
IGUIEditBox *
EditAlpha;
gui::
IGUIEditBox *
EditRed;
gui::
IGUIEditBox *
EditGreen;
gui::
IGUIEditBox *
EditBlue;
}
;
II-A. Édition des couleurs▲
Un contrôleur d'interface utilisateur personnalisé pour éditer toutes les couleurs typiquement utilisées dans les matériels et les lumières.
class
CAllColorsControl : public
gui::
IGUIElement
{
public
:
// Constructeur.
CAllColorsControl(gui::
IGUIEnvironment*
guiEnv, const
core::
position2d<
s32>
&
pos, const
wchar_t
*
description, bool
hasEmissive, IGUIElement*
parent, s32 id=-
1
)
:
gui::
IGUIElement(gui::
EGUIET_ELEMENT, guiEnv, parent,id, core::
rect<
s32>
(pos,pos+
core::
dimension2d<
s32>
(60
,250
)))
, ControlAmbientColor(0
), ControlDiffuseColor(0
), ControlSpecularColor(0
), ControlEmissiveColor(0
)
{
core::
rect<
s32>
rect(0
, 0
, 60
, 15
);
guiEnv->
addStaticText (description, rect, false
, false
, this
, -
1
, false
);
createColorControls(guiEnv, core::
position2d<
s32>
(0
, 15
), hasEmissive);
}
// Destructeur
virtual
~
CAllColorsControl()
{
ControlAmbientColor->
drop();
ControlDiffuseColor->
drop();
if
( ControlEmissiveColor )
ControlEmissiveColor->
drop();
ControlSpecularColor->
drop();
}
// Change les valeurs des couleurs pour celles contenues dans le matériel.
void
setColorsToMaterialColors(const
video::
SMaterial &
material)
{
ControlAmbientColor->
setColor(material.AmbientColor);
ControlDiffuseColor->
setColor(material.DiffuseColor);
ControlEmissiveColor->
setColor(material.EmissiveColor);
ControlSpecularColor->
setColor(material.SpecularColor);
}
// Met à jour toutes les couleurs changées dans le matériel.
void
updateMaterialColors(video::
SMaterial &
material)
{
if
( ControlAmbientColor->
isDirty() )
material.AmbientColor =
ControlAmbientColor->
getColor();
if
( ControlDiffuseColor->
isDirty() )
material.DiffuseColor =
ControlDiffuseColor->
getColor();
if
( ControlEmissiveColor->
isDirty() )
material.EmissiveColor =
ControlEmissiveColor->
getColor();
if
( ControlSpecularColor->
isDirty() )
material.SpecularColor =
ControlSpecularColor->
getColor();
}
// Change les valeurs des couleurs pour celles issues des données de la lumière.
void
setColorsToLightDataColors(const
video::
SLight &
lightData)
{
ControlAmbientColor->
setColor(lightData.AmbientColor.toSColor());
ControlAmbientColor->
setColor(lightData.DiffuseColor.toSColor());
ControlAmbientColor->
setColor(lightData.SpecularColor.toSColor());
}
// Met à jour toutes les couleurs modifiées dans les données de la lumière.
void
updateLightColors(video::
SLight &
lightData)
{
if
( ControlAmbientColor->
isDirty() )
lightData.AmbientColor =
video::
SColorf( ControlAmbientColor->
getColor() );
if
( ControlDiffuseColor->
isDirty() )
lightData.DiffuseColor =
video::
SColorf( ControlDiffuseColor->
getColor() );
if
( ControlSpecularColor->
isDirty() )
lightData.SpecularColor =
video::
SColorf(ControlSpecularColor->
getColor() );
}
// Réinitialise le fanion sale.
void
resetDirty()
{
ControlAmbientColor->
resetDirty();
ControlDiffuseColor->
resetDirty();
ControlSpecularColor->
resetDirty();
if
( ControlEmissiveColor )
ControlEmissiveColor->
resetDirty();
}
protected
:
void
createColorControls(gui::
IGUIEnvironment*
guiEnv, const
core::
position2d<
s32>
&
pos, bool
hasEmissive)
{
ControlAmbientColor =
new
CColorControl( guiEnv, pos, L"ambient"
, this
);
ControlDiffuseColor =
new
CColorControl( guiEnv, pos +
core::
position2d<
s32>
(0
, 75
), L"diffuse"
, this
);
ControlSpecularColor =
new
CColorControl( guiEnv, pos +
core::
position2d<
s32>
(0
, 150
), L"specular"
, this
);
if
( hasEmissive )
{
ControlEmissiveColor =
new
CColorControl( guiEnv, pos +
core::
position2d<
s32>
(0
, 225
), L"emissive"
, this
);
}
}
private
:
CColorControl*
ControlAmbientColor;
CColorControl*
ControlDiffuseColor;
CColorControl*
ControlSpecularColor;
CColorControl*
ControlEmissiveColor;
}
;
II-B. Sélection des textures▲
Un contrôleur d'interface utilisateur personnalisé pour offrir une sélection des textures disponibles.
class
CTextureControl : public
gui::
IGUIElement
{
public
:
CTextureControl(gui::
IGUIEnvironment*
guiEnv, video::
IVideoDriver *
driver, const
core::
position2d<
s32>
&
pos, IGUIElement*
parent, s32 id=-
1
)
:
gui::
IGUIElement(gui::
EGUIET_ELEMENT, guiEnv, parent,id, core::
rect<
s32>
(pos,pos+
core::
dimension2d<
s32>
(100
,15
)))
, DirtyFlag(true
), ComboTexture(0
)
{
core::
rect<
s32>
rectCombo(0
, 0
, AbsoluteRect.getWidth(),AbsoluteRect.getHeight());
ComboTexture =
guiEnv->
addComboBox (rectCombo, this
);
updateTextures(driver);
}
virtual
bool
OnEvent(const
SEvent &
event)
{
if
( event.EventType !=
EET_GUI_EVENT )
return
false
;
if
( event.GUIEvent.Caller ==
ComboTexture &&
event.GUIEvent.EventType ==
gui::
EGET_COMBO_BOX_CHANGED )
{
DirtyFlag =
true
;
}
return
false
;
}
// Contournement pour un problème avec les listes déroulantes.
// Nous devons obtenir le premier plan quand les listes déroulantes veulent aller au premier plan ou la liste déroulante peut être dessinée sous les autres éléments.
virtual
bool
bringToFront(IGUIElement*
element)
{
bool
result =
gui::IGUIElement::
bringToFront(element);
if
( Parent &&
element ==
ComboTexture )
result &=
Parent->
bringToFront(this
);
return
result;
}
// Retourne le nom de la texture sélectionnée, (si aucun retourne 0).
const
wchar_t
*
getSelectedTextureName() const
{
s32 selected =
ComboTexture->
getSelected();
if
( selected <
0
)
return
0
;
return
ComboTexture->
getItem(selected);
}
// Réinitialise le fanion sale.
void
resetDirty()
{
DirtyFlag =
false
;
}
// Quand la texture a été changée, le fanion sale est posé.
bool
isDirty() const
{
return
DirtyFlag;
}
;
// Met les noms de toutes les textures chargées dans une liste déroulante.
void
updateTextures(video::
IVideoDriver *
driver)
{
s32 oldSelected =
ComboTexture->
getSelected();
s32 selectNew =
-
1
;
const
wchar_t
*
oldTextureName =
0
;
if
( oldSelected >=
0
)
{
oldTextureName =
ComboTexture->
getItem(oldSelected);
}
ComboTexture->
clear();
for
( u32 i=
0
; i <
driver->
getTextureCount(); ++
i )
{
video::
ITexture *
texture =
driver->
getTextureByIndex(i);
core::
stringw name( texture->
getName() );
ComboTexture->
addItem( name.c_str() );
if
( oldTextureName &&
selectNew <
0
&&
name ==
oldTextureName )
selectNew =
i;
}
// Ajoute un autre nom qui peut être utilisé pour effacer la texture.
ComboTexture->
addItem( CLEAR_TEXTURE.c_str() );
if
( CLEAR_TEXTURE ==
oldTextureName )
selectNew =
ComboTexture->
getItemCount()-
1
;
if
( selectNew >=
0
)
ComboTexture->
setSelected(selectNew);
DirtyFlag =
true
;
}
private
:
bool
DirtyFlag;
gui::
IGUIComboBox *
ComboTexture;
}
;
II-C. Configuration de matériel▲
Contrôleur qui autorise la configuration de certaines valeurs de matériel d'un MeshSceneNode.
struct
SMeshNodeControl
{
// Constructeur.
SMeshNodeControl()
:
Initialized(false
), Driver(0
), MeshManipulator(0
), SceneNode(0
), SceneNode2T(0
), SceneNodeTangents(0
)
, AllColorsControl(0
), ButtonLighting(0
), InfoLighting(0
), ComboMaterial(0
), TextureControl1(0
), TextureControl2(0
), ControlVertexColors(0
)
{
}
// Destructeur.
virtual
~
SMeshNodeControl()
{
if
( TextureControl1 )
TextureControl1->
drop();
if
( TextureControl2 )
TextureControl2->
drop();
if
( ControlVertexColors )
ControlVertexColors->
drop();
if
( AllColorsControl )
AllColorsControl->
drop();
}
void
init(scene::
IMeshSceneNode*
node, IrrlichtDevice *
device, const
core::
position2d<
s32>
&
pos, const
wchar_t
*
description)
{
if
( Initialized ||
!
node ||
!
device) // initialisé deux fois ou avec une donnée invalide non autorisée.
return
;
Driver =
device->
getVideoDriver ();
gui::
IGUIEnvironment*
guiEnv =
device->
getGUIEnvironment();
scene::
ISceneManager*
smgr =
device->
getSceneManager();
MeshManipulator =
smgr->
getMeshManipulator();
SceneNode =
node;
scene::
IMeshManipulator *
meshManip =
smgr->
getMeshManipulator();
scene::
IMesh *
mesh2T =
meshManip->
createMeshWith2TCoords(node->
getMesh());
SceneNode2T =
smgr->
addMeshSceneNode(mesh2T, 0
, -
1
, SceneNode->
getPosition(), SceneNode->
getRotation(), SceneNode->
getScale() );
mesh2T->
drop();
scene::
IMesh *
meshTangents =
meshManip->
createMeshWithTangents(node->
getMesh(), false
, false
, false
);
SceneNodeTangents =
smgr->
addMeshSceneNode(meshTangents, 0
, -
1
, SceneNode->
getPosition(), SceneNode->
getRotation(), SceneNode->
getScale() );
meshTangents->
drop();
video::
SMaterial &
material =
SceneNode->
getMaterial(0
);
material.Lighting =
true
;
AllColorsControl =
new
CAllColorsControl(guiEnv, pos, description, true
, guiEnv->
getRootGUIElement());
AllColorsControl->
setColorsToMaterialColors(material);
core::
rect<
s32>
rectBtn(pos +
core::
position2d<
s32>
(0
, 320
), core::
dimension2d<
s32>
(60
, 15
));
ButtonLighting =
guiEnv->
addButton (rectBtn, 0
, -
1
, L"Lighting"
);
ButtonLighting->
setIsPushButton(true
);
ButtonLighting->
setPressed(material.Lighting);
core::
rect<
s32>
rectInfo( rectBtn.LowerRightCorner.X, rectBtn.UpperLeftCorner.Y, rectBtn.LowerRightCorner.X+
40
, rectBtn.UpperLeftCorner.Y+
15
);
InfoLighting =
guiEnv->
addStaticText(L""
, rectInfo, true
, false
);
InfoLighting->
setTextAlignment(gui::
EGUIA_CENTER, gui::
EGUIA_CENTER );
core::
rect<
s32>
rectCombo(pos.X, rectBtn.LowerRightCorner.Y, pos.X+
100
, rectBtn.LowerRightCorner.Y+
15
);
ComboMaterial =
guiEnv->
addComboBox (rectCombo);
for
( int
i=
0
; i <=
(int
)video::
EMT_ONETEXTURE_BLEND; ++
i )
{
ComboMaterial->
addItem( core::
stringw(video::
sBuiltInMaterialTypeNames[i]).c_str() );
}
ComboMaterial->
setSelected( (s32)material.MaterialType );
core::
position2d<
s32>
posTex(rectCombo.UpperLeftCorner.X,rectCombo.LowerRightCorner.Y);
TextureControl1 =
new
CTextureControl(guiEnv, Driver, posTex, guiEnv->
getRootGUIElement());
posTex.Y +=
15
;
TextureControl2 =
new
CTextureControl(guiEnv, Driver, posTex, guiEnv->
getRootGUIElement());
core::
position2d<
s32>
posVertexColors( posTex.X, posTex.Y +
15
);
ControlVertexColors =
new
CColorControl( guiEnv, posVertexColors, L"Vertex colors"
, guiEnv->
getRootGUIElement());
video::
S3DVertex *
vertices =
(video::
S3DVertex *
)node->
getMesh()->
getMeshBuffer(0
)->
getVertices();
if
( vertices )
{
ControlVertexColors->
setColor(vertices[0
].Color);
}
Initialized =
true
;
}
void
update()
{
if
( !
Initialized )
return
;
video::
SMaterial &
material =
SceneNode->
getMaterial(0
);
video::
SMaterial &
material2T =
SceneNode2T->
getMaterial(0
);
video::
SMaterial &
materialTangents =
SceneNodeTangents->
getMaterial(0
);
s32 selectedMaterial =
ComboMaterial->
getSelected();
if
( selectedMaterial >=
(s32)video::
EMT_SOLID &&
selectedMaterial <=
(s32)video::
EMT_ONETEXTURE_BLEND)
{
video::
E_VERTEX_TYPE vertexType =
getVertexTypeForMaterialType((video::
E_MATERIAL_TYPE)selectedMaterial);
switch
( vertexType )
{
case
video::
EVT_STANDARD:
material.MaterialType =
(video::
E_MATERIAL_TYPE)selectedMaterial;
SceneNode->
setVisible(true
);
SceneNode2T->
setVisible(false
);
SceneNodeTangents->
setVisible(false
);
break
;
case
video::
EVT_2TCOORDS:
material2T.MaterialType =
(video::
E_MATERIAL_TYPE)selectedMaterial;
SceneNode->
setVisible(false
);
SceneNode2T->
setVisible(true
);
SceneNodeTangents->
setVisible(false
);
break
;
case
video::
EVT_TANGENTS:
materialTangents.MaterialType =
(video::
E_MATERIAL_TYPE)selectedMaterial;
SceneNode->
setVisible(false
);
SceneNode2T->
setVisible(false
);
SceneNodeTangents->
setVisible(true
);
break
;
}
}
updateMaterial(material);
updateMaterial(material2T);
updateMaterial(materialTangents);
if
( ButtonLighting->
isPressed() )
InfoLighting->
setText(L"on"
);
else
InfoLighting->
setText(L"off"
);
AllColorsControl->
resetDirty();
TextureControl1->
resetDirty();
TextureControl2->
resetDirty();
ControlVertexColors->
resetDirty();
}
void
updateTextures()
{
TextureControl1->
updateTextures(Driver);
TextureControl2->
updateTextures(Driver);
}
protected
:
void
updateMaterial(video::
SMaterial &
material)
{
AllColorsControl->
updateMaterialColors(material);
material.Lighting =
ButtonLighting->
isPressed();
if
( TextureControl1->
isDirty() )
{
material.TextureLayer[0
].Texture =
Driver->
getTexture( io::
path(TextureControl1->
getSelectedTextureName()) );
}
if
( TextureControl2->
isDirty() )
{
material.TextureLayer[1
].Texture =
Driver->
getTexture( io::
path(TextureControl2->
getSelectedTextureName()) );
}
if
( ControlVertexColors->
isDirty() )
{
MeshManipulator->
setVertexColors (SceneNode->
getMesh(), ControlVertexColors->
getColor());
MeshManipulator->
setVertexColors (SceneNode2T->
getMesh(), ControlVertexColors->
getColor());
MeshManipulator->
setVertexColors (SceneNodeTangents->
getMesh(), ControlVertexColors->
getColor());
}
}
bool
Initialized;
video::
IVideoDriver *
Driver;
scene::
IMeshManipulator*
MeshManipulator;
scene::
IMeshSceneNode*
SceneNode;
scene::
IMeshSceneNode*
SceneNode2T;
scene::
IMeshSceneNode*
SceneNodeTangents;
CAllColorsControl*
AllColorsControl;
gui::
IGUIButton *
ButtonLighting;
gui::
IGUIStaticText*
InfoLighting;
gui::
IGUIComboBox *
ComboMaterial;
CTextureControl*
TextureControl1;
CTextureControl*
TextureControl2;
CColorControl*
ControlVertexColors;
}
;
II-D. Configuration du gestionnaire de lumières▲
Contrôleur pour autoriser la configuration des valeurs des couleurs d'un LightSceneNode.
struct
SLightNodeControl
{
// Constructeur.
SLightNodeControl() : Initialized(false
), SceneNode(0
), AllColorsControl(0
)
{
}
virtual
~
SLightNodeControl()
{
if
( AllColorsControl )
AllColorsControl->
drop();
}
void
init(scene::
ILightSceneNode*
node, gui::
IGUIEnvironment*
guiEnv, const
core::
position2d<
s32>
&
pos, const
wchar_t
*
description)
{
if
( Initialized ||
!
node ||
!
guiEnv) // initializing twice or with invalid data not allowed
return
;
SceneNode =
node;
AllColorsControl =
new
CAllColorsControl(guiEnv, pos, description, false
, guiEnv->
getRootGUIElement());
const
video::
SLight &
lightData =
SceneNode->
getLightData();
AllColorsControl->
setColorsToLightDataColors(lightData);
Initialized =
true
;
}
void
update()
{
if
( !
Initialized )
return
;
video::
SLight &
lightData =
SceneNode->
getLightData();
AllColorsControl->
updateLightColors(lightData);
}
protected
:
bool
Initialized;
scene::
ILightSceneNode*
SceneNode;
CAllColorsControl*
AllColorsControl;
}
;
III. Configuration de l'application▲
Configuration de l'application.
struct
SConfig
{
SConfig()
:
RenderInBackground(true
)
, DriverType(video::
EDT_BURNINGSVIDEO)
, ScreenSize(640
, 480
)
{
}
bool
RenderInBackground;
video::
E_DRIVER_TYPE DriverType;
core::
dimension2d<
u32>
ScreenSize;
}
;
IV. Classe principale▲
Classe principale de l'application.
class
CApp : public
IEventReceiver
{
friend
int
main(int
argc, char
*
argv[]);
public
:
// Constructeur.
CApp()
:
IsRunning(false
)
, Device(0
)
, Camera(0
)
, GlobalAmbient(0
)
{
}
// Destructeur.
~
CApp()
{
}
// Arrête l'exécution – quittera à la fin de la boucle principale.
void
stopApp()
{
IsRunning =
false
;
}
// Gestionnaire d'événements.
virtual
bool
OnEvent(const
SEvent &
event)
{
if
(event.EventType ==
EET_GUI_EVENT)
{
gui::
IGUIEnvironment*
env =
Device->
getGUIEnvironment();
switch
(event.GUIEvent.EventType)
{
case
gui::
EGET_MENU_ITEM_SELECTED:
{
gui::
IGUIContextMenu*
menu =
(gui::
IGUIContextMenu*
)event.GUIEvent.Caller;
s32 id =
menu->
getItemCommandId(menu->
getSelectedItem());
switch
(id)
{
case
GUI_ID_OPEN_TEXTURE: // File -> Open Texture
env->
addFileOpenDialog(L"Please select a texture file to open"
);
break
;
case
GUI_ID_QUIT: // File -> Quit
stopApp();
break
;
}
}
break
;
case
gui::
EGET_FILE_SELECTED:
{
// load the model file, selected in the file open dialog
gui::
IGUIFileOpenDialog*
dialog =
(gui::
IGUIFileOpenDialog*
)event.GUIEvent.Caller;
loadTexture(io::
path(dialog->
getFileName()).c_str());
}
break
;
default
:
break
;
}
}
return
false
;
}
protected
:
// Initialisation de l'application.
// Retourne true quand elle a été correctement initialisée, sinon retourne false.
bool
init(int
argc, char
*
argv[])
{
// Demande à l'utilisateur un pilote.
Config.DriverType=
driverChoiceConsole();
if
(Config.DriverType==
video::
EDT_COUNT)
return
false
;
// Crée le moteur avec les options issues de notre configuration.
Device =
createDevice(Config.DriverType, Config.ScreenSize);
if
(!
Device)
return
false
;
Device->
setWindowCaption( DriverTypeNames[Config.DriverType] );
Device->
setEventReceiver(this
);
scene::
ISceneManager*
smgr =
Device->
getSceneManager();
video::
IVideoDriver *
driver =
Device->
getVideoDriver ();
gui::
IGUIEnvironment*
guiEnv =
Device->
getGUIEnvironment();
// Met une jolie police.
gui::
IGUISkin*
skin =
guiEnv->
getSkin();
gui::
IGUIFont*
font =
guiEnv->
getFont("../../media/fonthaettenschweiler.bmp"
);
if
(font)
skin->
setFont(font);
// Supprime quelques valeurs alpha rendant les menus plus difficiles à lire.
video::
SColor col3dHighLight( skin->
getColor(gui::
EGDC_APP_WORKSPACE) );
col3dHighLight.setAlpha(255
);
video::
SColor colHighLight( col3dHighLight );
skin->
setColor(gui::
EGDC_HIGH_LIGHT, colHighLight );
skin->
setColor(gui::
EGDC_3D_HIGH_LIGHT, col3dHighLight );
// Ajoute quelques textures qui sont utiles pour tester les options des matériels.
createDefaultTextures(driver);
// Crée un menu.
gui::
IGUIContextMenu *
menuBar =
guiEnv->
addMenu();
menuBar->
addItem(L"File"
, -
1
, true
, true
);
gui::
IGUIContextMenu*
subMenuFile =
menuBar->
getSubMenu(0
);
subMenuFile->
addItem(L"Open texture ..."
, GUI_ID_OPEN_TEXTURE);
subMenuFile->
addSeparator();
subMenuFile->
addItem(L"Quit"
, GUI_ID_QUIT);
// Une caméra statique.
Camera =
smgr->
addCameraSceneNode (0
, core::
vector3df(0
, 0
, 0
),
core::
vector3df(0
, 0
, 100
),
-
1
);
// Ajoute les nœuds qui sont utilisés pour montrer les matériels.
scene::
IMeshSceneNode*
nodeL =
smgr->
addCubeSceneNode (30.0
f, 0
, -
1
,
core::
vector3df(-
35
, 0
, 100
),
core::
vector3df(0
, 0
, 0
),
core::
vector3df(1.0
f, 1.0
f, 1.0
f));
NodeLeft.init( nodeL, Device, core::
position2d<
s32>
(10
,20
), L"left node"
);
scene::
IMeshSceneNode*
nodeR =
smgr->
addCubeSceneNode (30.0
f, 0
, -
1
,
core::
vector3df(35
, 0
, 100
),
core::
vector3df(0
, 0
, 0
),
core::
vector3df(1.0
f, 1.0
f, 1.0
f));
NodeRight.init( nodeR, Device, core::
position2d<
s32>
(530
,20
), L"right node"
);
// Ajoute une lumière.
scene::
ILightSceneNode*
nodeLight =
smgr->
addLightSceneNode(0
, core::
vector3df(0
, 0
, 0
),
video::
SColorf(1.0
f, 1.0
f, 1.0
f),
100.0
f);
LightControl.init(nodeLight, guiEnv, core::
position2d<
s32>
(270
,20
), L"light"
);
// Un large cube englobant le tout. C'est principalement pour rendre la lumière plus évidente.
scene::
IMeshSceneNode*
backgroundCube =
smgr->
addCubeSceneNode (200.0
f, 0
, -
1
, core::
vector3df(0
, 0
, 0
),
core::
vector3df(45
, 0
, 0
),
core::
vector3df(1.0
f, 1.0
f, 1.0
f));
backgroundCube->
getMaterial(0
).BackfaceCulling =
false
; // Nous sommes à l'intérieur du cube donc nous devons désactiver le « backface culling » pour le voir.
backgroundCube->
getMaterial(0
).EmissiveColor.set(255
,50
,50
,50
); // Nous conservons quelques lumières pour garder les textes visibles.
// Met la valeur de la lumière ambiante.
GlobalAmbient =
new
CColorControl( guiEnv, core::
position2d<
s32>
(270
, 300
), L"global ambient"
, guiEnv->
getRootGUIElement());
GlobalAmbient->
setColor( smgr->
getAmbientLight().toSColor() );
return
true
;
}
// Met à jour une image.
bool
update()
{
using
namespace
irr;
video::
IVideoDriver*
videoDriver =
Device->
getVideoDriver();
if
( !
Device->
run() )
return
false
;
if
( Device->
isWindowActive() ||
Config.RenderInBackground )
{
gui::
IGUIEnvironment*
guiEnv =
Device->
getGUIEnvironment();
scene::
ISceneManager*
smgr =
Device->
getSceneManager();
gui::
IGUISkin *
skin =
guiEnv->
getSkin();
// Met à jour nos contrôleurs.
NodeLeft.update();
NodeRight.update();
LightControl.update();
// Met à jour la configuration de la lumière ambiante.
if
( GlobalAmbient->
isDirty() )
{
smgr->
setAmbientLight( GlobalAmbient->
getColor() );
GlobalAmbient->
resetDirty();
}
// Dessine tout.
video::
SColor bkColor( skin->
getColor(gui::
EGDC_APP_WORKSPACE) );
videoDriver->
beginScene(true
, true
, bkColor);
smgr->
drawAll();
guiEnv->
drawAll();
videoDriver->
endScene();
}
return
true
;
}
// Exécute l'application. Notre boucle principale.
void
run()
{
IsRunning =
true
;
if
( !
Device )
return
;
// Boucle principale de l'application.
while
(IsRunning)
{
if
( !
update() )
break
;
Device->
sleep( 5
);
}
}
// Ferme l'application.
void
quit()
{
IsRunning =
false
;
GlobalAmbient->
drop();
GlobalAmbient =
NULL
;
if
( Device )
{
Device->
closeDevice();
Device->
drop();
Device =
NULL
;
}
}
// Crée quelques textures utiles.
// Notez que la fonction peut privilégier la lisibilité sur la vitesse de rendu, vous ne devez pas utiliser setPixel pendant l'exécution mais à l'initialisation.
void
createDefaultTextures(video::
IVideoDriver *
driver)
{
const
u32 width =
256
;
const
u32 height =
256
;
video::
IImage *
imageA8R8G8B8 =
driver->
createImage (video::
ECF_A8R8G8B8, core::
dimension2d<
u32>
(width, height));
if
( !
imageA8R8G8B8 )
return
;
const
u32 pitch =
imageA8R8G8B8->
getPitch();
// Quelques modèles carrés sympathiques avec neuf couleurs typiques.
for
( u32 y =
0
; y <
height; ++
y )
{
for
( u32 x =
0
; x <
pitch; ++
x )
{
if
( y <
height/
3
)
{
if
( x <
width/
3
)
imageA8R8G8B8->
setPixel (x, y, SCOL_BLACK);
else
if
( x <
2
*
width/
3
)
imageA8R8G8B8->
setPixel (x, y, SCOL_BLUE);
else
imageA8R8G8B8->
setPixel (x, y, SCOL_CYAN);
}
else
if
( y <
2
*
height/
3
)
{
if
( x <
width/
3
)
imageA8R8G8B8->
setPixel (x, y, SCOL_GRAY);
else
if
( x <
2
*
width/
3
)
imageA8R8G8B8->
setPixel (x, y, SCOL_GREEN);
else
imageA8R8G8B8->
setPixel (x, y, SCOL_MAGENTA);
}
else
{
if
( x <
width/
3
)
imageA8R8G8B8->
setPixel (x, y, SCOL_RED);
else
if
( x <
2
*
width/
3
)
imageA8R8G8B8->
setPixel (x, y, SCOL_YELLOW);
else
imageA8R8G8B8->
setPixel (x, y, SCOL_WHITE);
}
}
}
driver->
addTexture (io::
path("CARO_A8R8G8B8"
), imageA8R8G8B8);
// Tout blanc.
imageA8R8G8B8->
fill(SCOL_WHITE);
driver->
addTexture (io::
path("WHITE_A8R8G8B8"
), imageA8R8G8B8);
// Tout noir.
imageA8R8G8B8->
fill(SCOL_BLACK);
driver->
addTexture (io::
path("BLACK_A8R8G8B8"
), imageA8R8G8B8);
// Nuances de gris.
for
( u32 y =
0
; y <
height; ++
y )
{
for
( u32 x =
0
; x <
pitch; ++
x )
{
imageA8R8G8B8->
setPixel (x, y, video::
SColor(y, x,x,x) );
}
}
driver->
addTexture (io::
path("GRAYSCALE_A8R8G8B8"
), imageA8R8G8B8);
imageA8R8G8B8->
drop();
}
// Charge la texture et s'assure que les nœuds savent lorsque d'autres textures sont disponibles.
void
loadTexture(const
io::
path &
name)
{
Device->
getVideoDriver()->
getTexture(name);
NodeLeft.updateTextures();
NodeRight.updateTextures();
}
private
:
SConfig Config;
volatile
bool
IsRunning;
IrrlichtDevice *
Device;
scene::
ICameraSceneNode *
Camera;
SMeshNodeControl NodeLeft;
SMeshNodeControl NodeRight;
SLightNodeControl LightControl;
CColorControl *
GlobalAmbient;
}
;
V. Main▲
Un main vraiment court comme nous avons tout fait dans les classes.
int
main(int
argc, char
*
argv[])
{
CApp APP;
if
( !
APP.init(argc, argv) )
{
printf("init failed
\n
"
);
return
1
;
}
APP.run();
APP.quit();
return
0
;
}
VI. Conclusion▲
Vous pouvez désormais visualiser des matériels, tester leurs options et regarder les résultats.
Dans le prochain tutoriel SMeshBufferHandling, nous verrons comment créer des meshs personnalisés et les utiliser avec Irrlicht.
VII. Remerciements▲
Merci à Nikolaus Gebhardt de nous permettre de traduire ce tutoriel.
Merci à LittleWhite pour sa relecture technique ainsi qu'à ClaudeLELOUP pour sa relecture orthographique.