Yo à tous !
On me l'avait demandé, je l'avais promis, et je l'ai fait ! Hahaha...
Plus sérieusement, j'aurais aimé fournir un travail un peu mieux fait que ça, mais bon...
C'est pour ça que je suis prêt à répondre à toutes les questions, alors n'hésitez pas.
Vous trouverez le code source ainsi que quelques explications ici :
http://aranoth.keogratuit.com/?p=5
Ou si le baratin ne vous intéresse pas :
http://aranoth.keogratuit.com/LoaderDXS.rar
Voilà
En espérant que ça puisse aider certains malgré l'aspect chaotique du code...
Hors ligne
yop
'peut être très utile pour les .NETeux
bon boulot
Hors ligne
hehe, merci beaucoup Aranoth. Avec ça et le loader de ilbuzzo (celui en C++) je devrais pouvoir me dépatouiller pour intégrer ça a mon projet.
EDIT : bon je vais passer pour un grincheux, mais je vais te donner un conseil "pour plus tard" : prends l'habitude de commenter ton code. Pas juste des summary sur les fields des classes. exemple : un "// Identifiant" sur un "public int Id" par exemple est inutile. Deja parce que le nom du field est "autodescriptif" (dans la mesure du possible), donc ce commentaire est redondant, et n'apporte aucune indication sur l'utilité du champ.
Ensuite, toutes tes méthodes ne sont pas commentées. En tant que développeur, j'aime bien ne pas perdre du temps a lire le code pour savoir ce qu'il fait. C'est là qu'un ///<summary> serait le bienvenu, pour décrire rapidos le fonctionnement de la méthode, expliquer succintement comment tu geres tel ou tel truc.
Je dis pas que c'est du mauvais code, mais reviens y dans un an, et tu vas etre réticent a te replonger dedans pour lire ton code pour essayer de te souvenir comment tu as fait. Le commentaire est là pour te servir, et pour servir à ceux qui te liront.
Sinon le code ? J'y retourne. Et comme j'avais deja ecrit des trucs pour ça, je vais etudier les sections sur l'intégration dans irrlicht, et retoucher mes classes .
tiens, un exemple de code "bien" commenté (extrait des sources du wrapper .NetCP)
/// <summary> /// Creates a copy of the mesh, which will only consist of S3DVertexTangents vertices. /// This is useful if you want to draw tangent space normal mapped geometry because it calculates the tangent and binormal data which is needed there. /// </summary> /// <param name="baseMesh">Input mesh</param> /// <returns>Mesh consiting only of S3DVertexTangents vertices.</returns> public Mesh CreateMeshWithTangents(Mesh baseMesh) { return (Mesh) NativeElement.GetObject(MeshManipulator_CreateMeshWithTangents(_raw, baseMesh.Raw), typeof(Mesh)); }
d'autant plus interessant qu'il prends en compte les spécificités de .Net et de ses capacité de gestion de création de documentation. Le summary apparaitra dans l'intellisense. Les <param name> feront apparaitre la descrition des parametres formels dans l'intellisense quand on navigue dans les parametres. Là, j'ai pas besoin de lire le code pour savoir comment l'utiliser ni pour savoir ce que ça fait
No offense hein, mais bon, je suis en croisade contre les codes non commentés
Dernière modification par Ravine (23-06-2007 12:45:20)
Hors ligne
Héhé, justement j'ai rajouté les <summary> vite fait sans prendre le temps de réellement me replonger dans le code (si on met pas de <summary> le compilo crache un Warning...).
Oui c'était absolument pas commenté, je l'ai dit : il aurait fallut que j'écrive ce code en pensant dès le début à diffuser les sources.
Comme tu l'as dit, y revenir après c'est dur, et pas besoin d'attendre un an. J'ai pas pu m'y replonger correctement, les dépendances ont été enlevées vite fait, le code est vraiment pas utilisable en l'état.
C'est pour ça que je suis pret à répondre à toutes les questions, parce que j'ai bien conscience que ce code n'est exploitable tel quel.
Hors ligne
huhu pas de soucis. Deja de mon coté j'avais réalisé une grosse part du boulot. Je charge un DXS dans une classe perso (identifier tous les bidules du format DXS ça représente un sacré boulot mine de rien ). Mais il me manquait concretement toute la partie "envoi dans irrlicht". Mais je note, et n'hesiterai pas a te harceler
Hors ligne
Ah bah nous y voilà. Bon j'ai maté ton code et j'avoue que j'ai juste super rien a dire sur le code en lui meme
C'est propre et tout. Quelques questions cependant
ArrayList Vertices = new ArrayList();
foreach (AGE.XML.Node vert in vertices.Childs)
{
int id = Convert.ToInt32(vert.GetAttribute("id").Value);
float x = this.ValF(vert.GetAttribute("x").Value);
float y = this.ValF(vert.GetAttribute("y").Value);
float z = -this.ValF(vert.GetAttribute("z").Value);
Vertices.Add(new vector3d(x, y, z));
}
1- Une raison particuliere au choix d'un ArrayList plutot que toute autre implémentation de type list ? (juste pour info, ça m'interesse)
2- un petit détail interessant : le float z que tu multiplie par -1. Je suppose que c'est pour une obscure raison de changement de repere (main droite / main gauche), mais j'avoue que je preferai l'explication plutot que mes vagues considérations là dessus
Dernière modification par Ravine (27-06-2007 01:37:21)
Hors ligne
Peut-être que, list<> étant dans les Generics (donc dans la version 2.0 du framework), il a choisi de rester avec des librairies de 1.1 !
Bon le choix est étrange quand on sait que le wrapper est fait pour la 2.0...
Sinon je ne vois pas de raison possible à l'utilisation des ArrayList pour contenir un seul type d'objet, les list typées sont plus rapides, plus sûres et plus efficaces !
Hors ligne
Pour le signe moins devant la coordonnée Z c'est effectivement un changement de repère (ceux d'Irrlicht et de DeleD sont différents).
Pour le ArrayList Vertices, cela viens de là :
J'ai besoin d'accéder à une entrée par son ID, d'où le choix de l'ArrayList.
Mais comme j'ai appris le C# sur le tas, il est possible qu'il y ai une meilleur solution, c'est juste que dans ma tête l'ArrayList est l'équivalant du std::vector du C++.
Hors ligne
Je profite d'avoir uploadé ma version du loader sur mon blog (un referer me signalait que quelqu'un cherchait des infos sur les fichiers Dxs et comment les lire) pour bumper ici et balancer le meme lien.
http://ravine.blog.free.fr/blog/wp-cont … Loader.zip
le Dxs.cs contient des bouts de code d'un peu partout, donc je ne sais pas quelle licence lui mettre, mais les autres fichiers .cs sont placés sous licence MIT.
et le manuel
// on créée une instance d'un dxs Dxs myDxs = new Dxs(); // on fait appel a LoadFromFile pour lire le Dxs et le charger en mémoire. // (ici, je fais appel directement au fichier car il est dans le rep courant de l'application // et que le workingDirectory de irrlicht est mis à "./" myDxs.LoadFromFile("moyen.dxs"); // CreateMesh(IrrlichtDevice device, string texturePath) renvoie un Mesh tout propre, créé a partir des listes de myDxs Mesh dxsMesh = myDxs.CreateMesh(device, ""); // et hop, on l'ajoute au scene manager (dans un octree, etant donné que le mesh est statique. // C'est plus performant selon des personnes plus calées, y'a donc pas de raison de ne pas les écouter) SceneNode node = smgr.AddOctTreeSceneNode(dxsMesh, null, 24, 1);
Hors ligne
J'en profite alors pour mettre en ligne un autre code plus récent, mieux commenté.
Il y a pas mal de dépendances, mais il est tout de même assez simple à comprendre.
using System; using System.Collections; using System.Collections.Generic; using System.Text; using System.io; using IrrlichtNETCP; using IrrlichtNETCP.Inheritable; namespace AGE { // Mesh loader chargeant le format DXS (DeleD) public class DXSMeshLoader : IMeshLoader { // Chemin des textures static public string TexturePath = ""; // Liste des materiaux Dictionary<int, Material> Materials = new Dictionary<int, Material>(); // Charge le mesh public Mesh Load(string file) { Mesh mesh = new Mesh(); XML.File xml = new AGE.XML.File(file); XML.Node NScene = xml.Root.GetChild(0); this.LoadMaterials(NScene.GetChild("materials")); this.LoadPrimitives(NScene.GetChild("primitives") , mesh); return mesh; } // Charge les primitives void LoadPrimitives(XML.Node NPrimitives , Mesh mesh) { // Parcours toutes les primitives foreach (XML.Node NPrimitive in NPrimitives.Childs) { // Tag (ex: eau, escaladable, destructible, etc) string Tag = NPrimitive.GetChild("tag").Text; // Parcours les vertices list<vector3d> VerticesPosition = new list<vector3d>(); foreach (XML.Node NVertex in NPrimitive.GetChild("vertices").Childs) { vector3d position = new vector3d(); position.X = Tools.ValF(NVertex.GetAttribute("x").Value); position.Y = Tools.ValF(NVertex.GetAttribute("y").Value); position.Z = -Tools.ValF(NVertex.GetAttribute("z").Value); VerticesPosition.Add(position); } // Parcours les polygones int OldMaterialID = -1; Primitive Primitive = null; foreach (XML.Node NPolygon in NPrimitive.GetChild("polygons").Childs) { // Identifiant du materiau à utiliser int MaterialID = Convert.ToInt32(NPolygon.GetAttribute("mid").Value); // Changement de matériau if (MaterialID != OldMaterialID) { // Creer une nouvelle primitive Primitive = new Primitive(); } // Recupère le materiau dans la liste if (Materials.ContainsKey(MaterialID)) Primitive.Material = Materials[MaterialID]; // Parcours les vertices int VertexNbr = 0; foreach (XML.Node NVertex in NPolygon.Childs) { // Identifiant de la position du vertex int VertexID = Convert.ToInt32(NVertex.GetAttribute("vid").Value); // Coordonnées UV float U0 = Tools.ValF(NVertex.GetAttribute("u0").Value); float V0 = Tools.ValF(NVertex.GetAttribute("v0").Value); float U1 = U0; float V1 = V0; if (NVertex.GetAttribute("u1") != null && NVertex.GetAttribute("v1") != null) { U1 = Tools.ValF(NVertex.GetAttribute("u1").Value); V1 = Tools.ValF(NVertex.GetAttribute("v1").Value); } // Position du vertex vector3d Position = VerticesPosition[VertexID]; // Creer un vertex Vertex3DT2 vertex = new Vertex3DT2(Position, new vector3d(), new Color(255, 255, 255, 255), new vector2d(U0, V0), new vector2d(U1, V1)); Primitive.AddVertex(vertex); VertexNbr++; } // Indices int High = VertexNbr - 1; // High, Low, Center int Low = 0; int Center = 0; int IndexOffset = Primitive.MeshBuffer.VertexCount; for (int v = 0; v < VertexNbr - 2; ++v) { // Calcul les indices if ((v & 1) > 0) Center = High - 1; else Center = Low + 1; // Ajoute les indices Primitive.AddIndex(IndexOffset + High); Primitive.AddIndex(IndexOffset + Low); Primitive.AddIndex(IndexOffset + Center); // Retrouve les vertices concernés Vertex3DT2 VertexCenter = Primitive.GetVertex(Center); Vertex3DT2 VertexLow = Primitive.GetVertex(Low); Vertex3DT2 VertexHigh = Primitive.GetVertex(High); // Calcul de la normale vector3d Normal = this.GetFaceNormal(VertexHigh.Position, VertexLow.Position, VertexCenter.Position); // Corrige les normales des vertices VertexCenter.Normal += Normal; VertexLow.Normal += Normal; VertexHigh.Normal += Normal; if ((v & 1) > 0) High--; else Low++; } Primitive.RemadeMeshBuffer(); // Changement de matériau, c'est donc une nouvelle primitive if (MaterialID != OldMaterialID) { // L'ajoute au mesh mesh.AddPrimitive(Primitive); OldMaterialID = MaterialID; } } } } // Charge les matériaux void LoadMaterials(XML.Node NMaterials) { // Parcours toutes les catégories foreach (XML.Node NCategory in NMaterials.Childs) { // Parcours tous les matériaux d'une catégorie foreach (XML.Node NMaterial in NCategory.Childs) { Material Material = new Material(); Material.Lighting = false; int ID = Convert.ToInt32(NMaterial.GetAttribute("id").Value); // Parcours les layers du matérial foreach (XML.Node NLayer in NMaterial.Childs) { // Charge le fichier image string type = NLayer.GetAttribute("type").Value; string file = NLayer.GetChild("texture").GetAttribute("file").Value; file = DXSMeshLoader.TexturePath + file; if (type == "texture") Material.Texture1 = GraphicManager.Instance.Driver.GetTexture(file); else if (type == "lightmap") { // Présence d'une lightmap Material.Texture2 = GraphicManager.Instance.Driver.GetTexture(file); Material.MaterialType = MaterialType.Lightmap; } } // Ajoute le material à la liste Materials.Add(ID, Material); } } } // Renvoit la normale d'une face vector3d GetFaceNormal(vector3d a, vector3d b, vector3d c) { vector3d o = new vector3d(); vector3d v1 = new vector3d(); vector3d v2 = new vector3d(); v1 = a - b; v2 = b - c; o.X = (v1.Y * v2.Z) - (v1.Z * v2.Y); o.Y = (v1.Z * v2.X) - (v1.X * v2.Z); o.Z = (v1.X * v2.Y) - (v1.Y * v2.X); float dist = (o.X * o.X) + (o.Y * o.Y) + (o.Z * o.Z); dist = (float)System.Math.Sqrt(dist); if (dist == 0.0f) dist = 0.001f; o /= dist; return o; } } }
Hors ligne