public static void Read(string fileName, ConversionSettings conversionSettings, ref DisplayList dsp, out Dictionary <string, TextureInfo> allMaterials, out string[] messages) { messages = new string[0]; if (conversionSettings.colorInterpretation == ConversionSettings.ColorInterpretation.Undefined) { if (!conversionSettings.DoColorInterpretationDialog()) { allMaterials = null; return; } } string rootDirectory = System.IO.Path.GetDirectoryName(fileName); System.Xml.XmlDataDocument doc = new XmlDataDocument(); doc.Load(fileName); XmlNamespaceManager mgr = new XmlNamespaceManager(doc.NameTable); mgr.AddNamespace("df", doc.DocumentElement.NamespaceURI); List <Subset> meshes = new List <Subset>(); XmlNode imageLibraryNode = doc.SelectSingleNode("//df:COLLADA/df:library_images", mgr); XmlNode materialLibraryNode = doc.SelectSingleNode("//df:COLLADA/df:library_materials", mgr); XmlNode effectLibraryNode = doc.SelectSingleNode("//df:COLLADA/df:library_effects", mgr); XmlNode geometryLibraryNode = doc.SelectSingleNode("//df:COLLADA/df:library_geometries", mgr); XmlNode sceneLibraryNode = doc.SelectSingleNode("//df:COLLADA/df:library_visual_scenes", mgr); XmlNodeList geometryNodes = sceneLibraryNode.SelectNodes("df:visual_scene/df:node/df:instance_geometry", mgr); bool flipYZ = doc.SelectSingleNode("//df:COLLADA/df:asset/df:up_axis", mgr).InnerText == "Z_UP"; allMaterials = new Dictionary <string, TextureInfo>(); allMaterials["<Undefined>"] = new TextureInfo(null); foreach (XmlNode geometryNode in geometryNodes) { XmlNode meshNode = geometryLibraryNode.SelectSingleNode("df:geometry[@id='" + geometryNode.Attributes["url"].Value.Remove(0, 1) + "']/df:mesh", mgr); XmlNode transformNode = geometryNode.SelectSingleNode("../df:matrix[@sid='transform']", mgr); Matrix transform = Matrix.identity; if (transformNode != null) { transform.m = Array.ConvertAll <string, float>(transformNode.InnerText.Split(' '), (s) => float.Parse(s, NumberStyles.Any, CultureInfo.InvariantCulture)); } Matrix normalTransform = transform.InvertTranspose(); foreach (XmlNode trianglesNode in meshNode.SelectNodes("df:triangles", mgr)) { Subset meshSubset = new Subset(); meshes.Add(meshSubset); List <Vertex> vertexBuffer = new List <Vertex>(); //final vertex buffer for this material List <int> indexBuffer = new List <int>(); //final index buffer for this material //Data to be read from XML XmlAttribute materialAttribute = trianglesNode.Attributes["material"]; if (materialAttribute == null) { messages = new string[] { "Mesh without materials found. Skipping..." }; continue; } string material = materialAttribute.Value; string effect = materialLibraryNode.SelectSingleNode("df:material[@id='" + material + "']/df:instance_effect", mgr).Attributes["url"].Value.Remove(0, 1); XmlNode effectNode = effectLibraryNode.SelectSingleNode("df:effect[@id='" + effect + "']/df:profile_COMMON", mgr); XmlNode textureNode = effectNode.SelectSingleNode("df:technique/*/df:diffuse/df:texture", mgr); if (textureNode == null) { meshSubset.Texture = allMaterials["<Undefined>"]; } else { string surfaceName = effectNode.SelectSingleNode("df:newparam[@sid='" + textureNode.Attributes["texture"].Value + "']/df:sampler2D/df:source", mgr).InnerText; string init_from = effectNode.SelectSingleNode("df:newparam[@sid='" + surfaceName + "']/df:surface/df:init_from", mgr).InnerText; string imageFileName = imageLibraryNode.SelectSingleNode("df:image[@id='" + init_from + "']/df:init_from", mgr).InnerText; string fullPath = imageFileName; if (imageFileName[1] != ':') //Path is not absolute. Make Absolute { fullPath = System.IO.Path.Combine(rootDirectory, imageFileName); } fullPath = Uri.UnescapeDataString(fullPath); if (!allMaterials.TryGetValue(imageFileName, out meshSubset.Texture)) { meshSubset.Texture = allMaterials[imageFileName] = new TextureInfo(fullPath); } } int vertexOffset, normalOffset, texCoordOffset, colorOffset; vertexOffset = normalOffset = texCoordOffset = colorOffset = -1; Vec3[] positions = null, normals = null; TexCoord[] texCoords = null; Color[] colors = null; XmlNode vertexNode = trianglesNode.SelectSingleNode("df:input[@semantic='VERTEX']", mgr); if (vertexNode != null) { XmlNode vertexSource = meshNode.SelectSingleNode("df:vertices[@id='" + vertexNode.Attributes["source"].Value.Remove(0, 1) + "']", mgr); XmlNode vertexSourceSource /*jeez pls give me vertex positions now*/ = meshNode.SelectSingleNode("df:source[@id='" + vertexSource.SelectSingleNode("df:input[@semantic='POSITION']", mgr).Attributes["source"].Value.Remove(0, 1) + "']", mgr); positions = ReadXMLVectorNode <Vec3>(vertexSourceSource, mgr); vertexOffset = int.Parse(vertexNode.Attributes["offset"].Value); } XmlNode normalNode = trianglesNode.SelectSingleNode("df:input[@semantic='NORMAL']", mgr); if (normalNode != null) { XmlNode normalSource = meshNode.SelectSingleNode("df:source[@id='" + normalNode.Attributes["source"].Value.Remove(0, 1) + "']", mgr); normals = ReadXMLVectorNode <Vec3>(normalSource, mgr); normalOffset = int.Parse(normalNode.Attributes["offset"].Value); } XmlNode texCoordNode = trianglesNode.SelectSingleNode("df:input[@semantic='TEXCOORD']", mgr); if (texCoordNode != null) { XmlNode texCoordSource = meshNode.SelectSingleNode("df:source[@id='" + texCoordNode.Attributes["source"].Value.Remove(0, 1) + "']", mgr); texCoords = ReadXMLVectorNode <TexCoord>(texCoordSource, mgr); texCoordOffset = int.Parse(texCoordNode.Attributes["offset"].Value); } XmlNode colorNode = trianglesNode.SelectSingleNode("df:input[@semantic='COLOR']", mgr); if (colorNode != null) { XmlNode colorSource = meshNode.SelectSingleNode("df:source[@id='" + colorNode.Attributes["source"].Value.Remove(0, 1) + "']", mgr); colors = ReadXMLVectorNode <Color>(colorSource, mgr); colorOffset = int.Parse(colorNode.Attributes["offset"].Value); } int[] indices = Array.ConvertAll(trianglesNode.SelectSingleNode("df:p", mgr).InnerText.Split(' '), (string s) => int.Parse(s)); Vertex[] vertices = new Vertex[int.Parse(trianglesNode.Attributes["count"].Value) * 3]; int stride = indices.Length / vertices.Length; int currentIndex = 0; Color defaultColor = new Color(); defaultColor.R = defaultColor.G = defaultColor.B = defaultColor.A = 1; for (int i = 0; i < vertices.Length; i++) { Vec3 position = positions == null ? new Vec3() : positions[indices[i * stride + vertexOffset]]; position = position.TransformPosition(transform); Vec3 normal = normals == null ? new Vec3() : normals[indices[i * stride + normalOffset]]; normal = normal.TransformNormal(normalTransform); TexCoord texCoord = texCoords == null ? new TexCoord() : texCoords[indices[i * stride + texCoordOffset]]; Color color = colors == null ? defaultColor : colors[indices[i * stride + colorOffset]]; vertices[i] = flipYZ ? new Vertex(new Vector3(position.X, position.Z, -position.Y), new Vector2(texCoord.S, texCoord.T), new Vector3(normal.X, normal.Z, -normal.Y)) : new Vertex(new Vector3(position.X, position.Y, position.Z), new Vector2(texCoord.S, texCoord.T), new Vector3(normal.X, normal.Y, normal.Z)); Color c = colors == null ? defaultColor : colors[indices[i * stride + 3]]; if (conversionSettings.colorInterpretation == ConversionSettings.ColorInterpretation.ReplaceNormal) { vertices[i].nx = (sbyte)(c.R * 255); vertices[i].ny = (sbyte)(c.G * 255); vertices[i].nz = (sbyte)(c.B * 255); vertices[i].c = 255; } else if (conversionSettings.colorInterpretation == ConversionSettings.ColorInterpretation.ConvertRedToAlpha) { vertices[i].c = (byte)(c.R * 255); } else if (conversionSettings.colorInterpretation == ConversionSettings.ColorInterpretation.ConvertGreenToAlpha) { vertices[i].c = (byte)(c.G * 255); } else if (conversionSettings.colorInterpretation == ConversionSettings.ColorInterpretation.ConvertBlueToAlpha) { vertices[i].c = (byte)(c.B * 255); } else if (conversionSettings.colorInterpretation == ConversionSettings.ColorInterpretation.ConvertRedToAlpha) { vertices[i].c = (byte)((c.R + c.G + c.B) / 3 * 255); } int k = 0; foreach (Vertex v in vertexBuffer) { if (v.Equals(vertices[i])) { indexBuffer.Add(k); goto skipNewVertex; } k++; } vertexBuffer.Add(vertices[i]); indexBuffer.Add(currentIndex++); skipNewVertex :; } meshSubset.IndexBuffer = indexBuffer.ToArray(); meshSubset.VertexBuffer = vertexBuffer.ToArray(); meshSubset.CreatePatches(); } } dsp.subsets = meshes.ToArray(); }
public static void Read(string fileName, ConversionSettings conversionSettings, ref DisplayList dsp, out Dictionary <string, TextureInfo> allMaterials, out string[] messages) { List <string> messageList = new List <string>(); string currentObject = ""; Subset LastFrame = null; List <Subset> Frames = new List <Subset>(); List <Vertex> Vertices = new List <Vertex>(); List <int> Indices = new List <int>(); List <FaceVertex> faceVertices = new List <FaceVertex>(); List <Vertex> dspVertexBuffer = new List <Vertex>(); List <int[]> dspIndexBuffers = new List <int[]>(); List <int> dspTextureKeys = new List <int>(); int[] dspIndices; int minVertexIndex = 0; List <Vector3> positions = new List <Vector3>(); List <Vector2> texCoords = new List <Vector2>(); List <Vector3> normals = new List <Vector3>(); allMaterials = new Dictionary <string, TextureInfo>(); allMaterials["<Undefined>"] = new TextureInfo(null); string[] fileNameSplit = fileName.Split(new char[] { '/', '\\' }); string fileRelativePath = fileName.Remove(fileName.Length - (fileNameSplit[fileNameSplit.Length - 1].Length), fileNameSplit[fileNameSplit.Length - 1].Length); if (!System.IO.File.Exists(fileName)) { messages = new string[] { "File " + fileName + " was not found." }; return; } StreamReader rd = new StreamReader(fileName); StreamReader materialReader = null; while (!rd.EndOfStream) { string line = rd.ReadLine(); string[] split = line.Split(' '); if (split[0] == "mtllib") { materialReader = new StreamReader(fileRelativePath + line.Remove(0, split[0].Length + 1)); string currentMtl = null; while (!materialReader.EndOfStream) { string matLine = materialReader.ReadLine(); string[] matSplit = matLine.Split(' '); if (matSplit[0] == "newmtl") { currentMtl = matLine.Remove(0, matSplit[0].Length); } if (matSplit[0] == "map_Kd") { TextureInfo newTex; string fullPath = matLine.Remove(0, matSplit[0].Length).Trim(); if (fullPath[1] != ':') { fullPath = fileRelativePath + fullPath; } allMaterials.Add(currentMtl, newTex = new TextureInfo(fullPath)); } } } else if (split[0] == "o") //Object { if (LastFrame == null) { LastFrame = new Subset(); } currentObject = split[1]; } else if (split[0] == "v") // Vertex { positions.Add(cvt.ParseVector3(split, 1)); } else if (split[0] == "vn")// Vertex Normal { normals.Add(cvt.ParseVector3(split, 1)); } else if (split[0] == "vt") // Vertex TexCoord { texCoords.Add(cvt.parseVector2(split, 1)); } else if (split[0] == "usemtl") { LastFrame.VertexBuffer = Vertices.ToArray(); LastFrame.IndexBuffer = Indices.ToArray(); dspIndices = new int[LastFrame.IndexBuffer.Length]; for (int i = 0; i < LastFrame.IndexBuffer.Length; i += 3) { dspIndices[i] = LastFrame.IndexBuffer[i + 2] + minVertexIndex; dspIndices[i + 1] = LastFrame.IndexBuffer[i + 1] + minVertexIndex; dspIndices[i + 2] = LastFrame.IndexBuffer[i] + minVertexIndex; } if (Indices.Count > 0) { dspIndexBuffers.Add(dspIndices); LastFrame.CreatePatches(); Frames.Add(LastFrame); } Indices.Clear(); LastFrame = new Subset(); string mtlName = line.Remove(0, split[0].Length); if (!allMaterials.TryGetValue(mtlName, out LastFrame.Texture)) { messageList.Add("Object " + currentObject + " has unassigned faces."); LastFrame.Texture = allMaterials["<Undefined>"]; } } else if (split[0] == "f") // Face { int i0 = 0, ix = 0; for (int i = 1; i < split.Length; i++) { string[] vertexIndices = split[i].Split('/'); FaceVertex faceVertex = new FaceVertex(); int.TryParse(vertexIndices[0], out faceVertex.Vertex); if (vertexIndices.Length > 1) { int.TryParse(vertexIndices[1], out faceVertex.Texture); } if (vertexIndices.Length > 2) { int.TryParse(vertexIndices[2], out faceVertex.Normal); } int index = 0; foreach (FaceVertex v in faceVertices) { if (v.Vertex == faceVertex.Vertex && v.Texture == faceVertex.Texture && v.Normal == faceVertex.Normal) { break; } index++; } if (i > 3) { Indices.Add(i0); Indices.Add(ix); } Indices.Add(index); if (i == 1) { i0 = index; } ix = index; if (index == faceVertices.Count) { faceVertices.Add(faceVertex); Vertex newVertex; Vector2 texCoord = Vector2.Empty; if (faceVertex.Texture > 0) { texCoord = texCoords[faceVertex.Texture - 1]; } Vector3 normal = Vector3.Empty; if (faceVertex.Normal > 0) { normal = normals[faceVertex.Normal - 1]; } Vertices.Add(newVertex = new Vertex(positions[faceVertex.Vertex - 1], texCoord, normal)); dspVertexBuffer.Add(newVertex); } } } } rd.BaseStream.Close(); materialReader.Close(); LastFrame.IndexBuffer = Indices.ToArray(); LastFrame.VertexBuffer = Vertices.ToArray(); dspIndices = new int[LastFrame.IndexBuffer.Length]; for (int i = 0; i < LastFrame.IndexBuffer.Length; i += 3) { dspIndices[i] = LastFrame.IndexBuffer[i + 2] + minVertexIndex; dspIndices[i + 1] = LastFrame.IndexBuffer[i + 1] + minVertexIndex; dspIndices[i + 2] = LastFrame.IndexBuffer[i] + minVertexIndex; } dspIndexBuffers.Add(dspIndices); LastFrame.CreatePatches(); Frames.Add(LastFrame); dsp.subsets = Frames.ToArray(); messages = messageList.ToArray(); }