1 Introduction
Nous continuons notre visite au pays de DirectX Managed avec aujourd’hui la mise en place de l’habillage de nos objets et du fichier de sauvegarde.

2 Fichier de sauvegarde
Une étape importante de notre développement va consister à définir une structure de stockage pour nos objets afin d’établir une bibliothèque riche pour définir nos meubles.
Dans le cadre d’InteriorWise, nous allons partir sur une solution basée sur XML pour garantir une lecture et une écriture facilitée des données. Ces fichiers XML vont donc se présenter sous cette forme :
<?xml version="1.0" encoding="utf-8" ?>
<object name="boite" texture="bewise.jpg" wireFrame="false" culling="true" x="0" y="0" z="3">
<vertices>
<vertex x="-1.0" y="1.0" z="-1.0" u="0" v="0"/>
<vertex x="1.0" y="1.0" z="-1.0" u="1" v="0"/>
<vertex x="1.0" y="-1.0" z="-1.0" u="1" v="1"/>
<vertex x="-1.0" y="-1.0" z="-1.0" u="0" v="1"/>
<vertex x="-1.0" y="1.0" z="1.0" u="0" v="0"/>
<vertex x="1.0" y="1.0" z="1.0" u="1" v="0"/>
<vertex x="1.0" y="-1.0" z="1.0" u="1" v="1"/>
<vertex x="-1.0" y="-1.0" z="1.0" u="0" v="1"/>
</vertices>
<faces>
<face a="0" b="1" c="2"/>
<face a="0" b="2" c="3"/>
<face a="6" b="5" c="4"/>
<face a="7" b="6" c="4"/>
<face a="0" b="5" c="1"/>
<face a="0" b="4" c="5"/>
<face a="3" b="2" c="6"/>
<face a="3" b="6" c="7"/>
<face a="7" b="4" c="0"/>
<face a="3" b="7" c="0"/>
<face a="1" b="5" c="6"/>
<face a="1" b="6" c="2"/>
</faces>
</object>
Le tag object va permettre de définir le nom de l’objet ainsi que sa position, ses options et le fichier image à utiliser pour définir sa texture.
Le tag vertices donne la liste des points avec leurs coordonnées de texture. Les points sont définis dans l’espace de l’objet. Il est nécessaire de produire un objet centré sur le zéro pour pouvoir par la suite le manipuler. Les coordonnées de texture seront définies dans le chapitre suivant.
Finalement, le tag faces donne les index de chaque point définissant une face. Dans le cadre où le culling est actif, il faudra faire attention à donner ces points dans le bon ordre.
Le code de lecture du fichier XML va se trouver dans la classe Object3D, au niveau de la méthode LoadFromXML :
public void LoadFromXml(string file)
{
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(file);
XmlNode obj = xmlDoc.SelectSingleNode("/object");
if (obj != null)
{
wireFrame = bool.Parse(obj.Attributes["wireFrame"].Value);
culling = bool.Parse(obj.Attributes["culling"].Value);
name = obj.Attributes["name"].Value;
position.X = float.Parse(obj.Attributes["x"].Value);
position.Y = float.Parse(obj.Attributes["y"].Value);
position.Z = float.Parse(obj.Attributes["z"].Value);
localTexture = Texture.FromBitmap(DirectXCore.device3D, (Bitmap)Bitmap.FromFile(obj.Attributes["texture"].Value), Usage.AutoGenerateMipMap, Pool.Managed);
XmlNode vertices = xmlDoc.SelectSingleNode("/object/vertices");
XmlNode faces = xmlDoc.SelectSingleNode("/object/faces");
mesh = new Mesh(faces.ChildNodes.Count, vertices.ChildNodes.Count, MeshFlags.Managed, CustomVertex.PositionTextured.Format, DirectXCore.device3D);
GraphicsStream data = mesh.LockIndexBuffer(LockFlags.None);
foreach (XmlNode face in faces.ChildNodes)
{
data.Write(short.Parse(face.Attributes["a"].Value));
data.Write(short.Parse(face.Attributes["b"].Value));
data.Write(short.Parse(face.Attributes["c"].Value));
}
mesh.UnlockIndexBuffer();
data = mesh.LockVertexBuffer(LockFlags.None);
foreach (XmlNode vertex in vertices.ChildNodes)
{
data.Write(float.Parse(vertex.Attributes["x"].Value));
data.Write(float.Parse(vertex.Attributes["y"].Value));
data.Write(float.Parse(vertex.Attributes["z"].Value));
data.Write(float.Parse(vertex.Attributes["u"].Value));
data.Write(float.Parse(vertex.Attributes["v"].Value));
}
mesh.UnlockVertexBuffer();
}
}
Pour la manipulation des flux de données d’un Mesh, DirectX Managed fournit une classe encapsulant tous les accès : le GraphicStream. Ce stream permet d’accéder aux données présentes sur la carte graphique (Vertex et/ou Index) de la même manière que n’importe quel autre flux. Les méthodes LockIndexBuffer et LockVertexBuffer permettent de produire ce GraphicStream.
La création manuelle du Mesh permet de définir que notre Mesh et son espace de travail seront entièrement gérés par DirectX Managed et qu’il contiendra des points de type CustomVertex.PositionTextured (3 flottants pour les positions et 2 flottants pour les coordonnées de texture).
3 Gestion des textures
Les textures sont des images qui serviront d’habillage aux objets. Pour ce faire, chaque point de chaque objet possède la coordonnée 2D d’un point sur la texture qui lui est attachée. Ainsi la carte graphique peut étirer la texture pour la plaquer sur l’objet :

Le chargement d’une texture se fait par la classe Texture :
localTexture = Texture.FromBitmap(DirectXCore.device3D, (Bitmap)Bitmap.FromFile(obj.Attributes["texture"].Value), Usage.AutoGenerateMipMap, Pool.Managed);
L’affectation lors du rendu se fait par simple appel à la méthode SetTexture :
DirectXCore.device3D.SetTexture(0, localTexture);
Cette méthode prend comme premier paramètre un entier car il est possible de mélanger plusieurs textures pour produire des effets complexes et variés.
4 Conclusion
Dans notre prochaine étape, nous intégrerons l’éclairage et les matériaux afin de simuler au mieux un environnement réaliste.