private void ReadMaterialIndices(uint numTriangles, MeshSerialFlags serialFlags, BinaryReader reader, bool platformMismatch) { if (serialFlags.HasFlag(MeshSerialFlags.MSF_MATERIALS)) { MaterialIndices = new List <ushort>((int)numTriangles); for (int i = 0; i < numTriangles; i++) { ushort mi = ReadWord(reader, platformMismatch); MaterialIndices.Add(mi); } } else { MaterialIndices.Clear(); } }
void Optimize() { needsOptimize = false; List <int> meshes = new List <int>(); bool didOptimise = false; List <MaterialIndices> mats = new List <MaterialIndices>(); for (int i = StartMesh; i < endMesh; i++) { var c = counts.Where((x) => x.Material == Mesh.Meshes[i].MaterialCrc).First(); if (c.Count == 1 || Mesh.Meshes[i].Material == null || Mesh.Meshes[i].Material.Render.IsTransparent) { meshes.Add(i); } else { didOptimise = true; var m = mats.Where((x) => x.Crc == Mesh.Meshes[i].MaterialCrc).FirstOrDefault(); if (m == null) { m = new MaterialIndices() { Crc = Mesh.Meshes[i].MaterialCrc }; mats.Add(m); } for (int j = Mesh.Meshes[i].TriangleStart; j < (Mesh.Meshes[i].TriangleStart + Mesh.Meshes[i].NumRefVertices); j++) { m.Indices.Add(Mesh.Indices[j] + StartVertex + Mesh.Meshes[i].StartVertex); } } } if (didOptimise) { List <OptimizedDrawcall> dcs = new List <OptimizedDrawcall>(); List <ushort> indices = new List <ushort>(); foreach (var m in mats) { var dc = new OptimizedDrawcall(); dc.MaterialCrc = m.Crc; dc.PrimitiveCount = m.Indices.Count / 3; dc.StartIndex = indices.Count + Mesh.IndexHandle.CountIndex; var min = m.Indices.Min(); for (int i = 0; i < m.Indices.Count; i++) { indices.Add((ushort)(m.Indices[i] - min)); } dc.VertexOffset = min + Mesh.VertexOffset; dc.vMeshLibrary = vMeshLibrary; dcs.Add(dc); } if (Mesh.IndexHandle.CountIndex + indices.Count >= Mesh.IndexHandle.TotalIndex) { FLLog.Warning("Vms", "Failed to optimise: Not enough space in element buffer"); return; } var arr = indices.ToArray(); mesh.IndexHandle.Elements.SetData(arr, arr.Length, Mesh.IndexHandle.CountIndex); mesh.IndexHandle.CountIndex += arr.Length; FLLog.Debug("Optimiser", "Reduced from " + MeshCount + " drawcalls to " + (meshes.Count + dcs.Count)); optimized = new OptimizedDraw(); optimized.NormalDraw = meshes.ToArray(); optimized.Optimized = dcs.ToArray(); } }
public void Parse() { this.Triangle.Clear(); this.TextureCoordinates.Clear(); this.Vertices.Clear(); bool newMesh = false; bool defaultMTL = false; int mtlIndex = 0; int meshIndex = 0; for (int i = 0; i < this.document.Length; i++) { string currLine = this.document[i].ToLower(); int valsInd = 0; string[] spli = currLine.Split(' '); bool waitForMtlLib = false; bool waitForMtl = false; bool vert = false; bool uv = false; bool triangle = false; float[] vals = new float[3]; string[] vals_S = new string[3]; for (int j = 0; j < spli.Length; j++) { if (spli[j] == "v") { vert = true; continue; } if (spli[j] == "vt") { uv = true; continue; } if (newMesh) { if (spli[j].Length > 0) { int indexOf = meshNames.IndexOf(spli[j]); if (spli[j].Length > 0 && indexOf < 0) { meshIndex = meshNames.Count; this.Triangle.Add(new List <int[]>(0)); meshNames.Add(spli[j]); MaterialIndices.Add(mtlIndex); } else { meshIndex = indexOf; //MaterialIndices.Add(mtlIndex); } } newMesh = false; continue; } if (spli[j] == "f") { triangle = true; continue; } if (spli[j] == "g") { newMesh = true; continue; } if (spli[j] == "mtllib") { waitForMtlLib = true; continue; } if (spli[j] == "usemtl") { waitForMtl = true; continue; } if (waitForMtl) { if (defaultMTL) { int indexOf = materialNames.IndexOf(spli[j]); if (indexOf < 0) { mtlIndex = materialNames.Count; if (File.Exists(this.DirectoryName + @"\" + spli[j].Replace("/", "\\"))) { materialFileNames.Add(this.DirectoryName + @"\" + spli[j].Replace("/", "\\")); } else { materialFileNames.Add(spli[j]); } materialNames.Add(spli[j]); } else { mtlIndex = indexOf; } } else { mtlIndex = materialNames.IndexOf(spli[j]); } MaterialIndices[meshIndex] = mtlIndex; waitForMtl = false; continue; } if (waitForMtlLib) { string[] mtl = new string[0]; if (File.Exists(this.DirectoryName + @"\" + spli[j].Replace("/", "\\"))) { mtl = File.ReadAllLines(this.DirectoryName + @"\" + spli[j].Replace("/", "\\")); } else if (File.Exists(spli[j])) { mtl = File.ReadAllLines(spli[j]); } if (mtl.Length > 0) { bool newMTL = false; bool waitForImage = false; for (int k = 0; k < mtl.Length; k++) { string currLine_ = mtl[k].ToLower(); string[] spli_ = currLine_.Split(' '); for (int l = 0; l < spli_.Length; l++) { if (spli_[l] == "newmtl") { newMTL = true; continue; } if (spli_[l] == "map_kd") { waitForImage = true; continue; } if (newMTL) { if (materialFileNames.Count < materialNames.Count) { materialFileNames.Add("noImage.png"); } materialNames.Add(spli_[l]); newMTL = false; } if (waitForImage) { if (File.Exists(this.DirectoryName + @"\" + spli_[l].Replace("/", "\\"))) { materialFileNames.Add(this.DirectoryName + @"\" + spli_[l].Replace("/", "\\")); } else { materialFileNames.Add(spli_[l]); } waitForImage = false; } } } } else { defaultMTL = true; } waitForMtlLib = false; continue; } float currVal = 0; if (Single.TryParse(spli[j].Replace(".", System.Globalization.CultureInfo.CurrentUICulture.NumberFormat.NumberDecimalSeparator), out currVal)) { vals[valsInd] = currVal; valsInd++; } if (spli[j].Contains("/")) { vals_S[valsInd] = spli[j]; valsInd++; } } if (vert) { float x = vals[0]; float y = vals[1]; float z = vals[2]; if (x > this.MaxCoords.X) { this.MaxCoords.X = x; } if (x < this.MinCoords.X) { this.MinCoords.X = x; } if (y > this.MaxCoords.Y) { this.MaxCoords.Y = y; } if (y < this.MinCoords.Y) { this.MinCoords.Y = y; } if (z > this.MaxCoords.Z) { this.MaxCoords.Z = z; } if (z < this.MinCoords.Z) { this.MinCoords.Z = z; } this.Vertices.Add(new Vector3(x, y, z)); vert = false; } if (uv) { this.TextureCoordinates.Add(new Vector2(vals[0], 1 - vals[1])); uv = false; } if (triangle) { for (int m = 0; m < vals_S.Length; m++) { string[] spli__ = vals_S[m].Split('/'); this.Triangle[meshIndex].Add(new int[3]); for (int n = 0; n < spli__.Length; n++) { this.Triangle[meshIndex].Last()[n] = int.Parse(spli__[n]) - 1; } } triangle = false; } } this.RenderBuffer = new VertexPositionColorTexture[this.Triangle.Count][]; for (int i = 0; i < this.RenderBuffer.Length; i++) { this.RenderBuffer[i] = new VertexPositionColorTexture[this.Triangle[i].Count]; for (int j = 0; j < this.RenderBuffer[i].Length; j++) { this.RenderBuffer[i][j] = new VertexPositionColorTexture(); } } }
public void Parse() { byte[] data = SrkBinary.GetBytesArray(this.FileName); string fileData = Encoding.ASCII.GetString(data); fileData = fileData.Replace("xmlns", "whocares"); this.Document.LoadXml(fileData); XmlNodeList materials = this.Document.SelectNodes("//library_materials/material"); if (materials != null) { for (int i = 0; i < materials.Count; i++) { string materialID = materials[i].SelectNodes("@id")[0].InnerText; string effectID = materials[i].SelectNodes("instance_effect/@url")[0].InnerText.Remove(0, 1); XmlNode effectNode = this.Document.SelectNodes("//library_effects/effect[@id='" + effectID + "']")[0]; string imageID = ""; XmlNodeList surfInitNode = effectNode.SelectNodes("profile_COMMON//surface/init_from"); if (surfInitNode != null && surfInitNode.Count > 0) { imageID = surfInitNode[0].InnerText; } XmlNodeList textureNode = effectNode.SelectNodes("profile_COMMON//texture/@texture"); if (imageID.Length == 0 && textureNode != null && textureNode.Count > 0) { imageID = textureNode[0].InnerText; } string fileName = this.Document.SelectNodes("//library_images/image[@id='" + imageID + "']/init_from")[0].InnerText; fileName = fileName.Replace("file://", ""); fileName = fileName.Replace("../", ""); fileName = fileName.Replace("./", ""); fileName = fileName.Replace("/", "\\"); if (Path.GetExtension(fileName).Length == 0) { string dir = Path.GetDirectoryName(fileName); bool notFoundExt = true; if (Directory.Exists(dir)) { string[] dirFiles = Directory.GetFiles(dir); for (int d = 0; d < dirFiles.Length; d++) { if (Path.GetFileNameWithoutExtension(dirFiles[d]) == Path.GetFileNameWithoutExtension(fileName)) { fileName += Path.GetExtension(dirFiles[d]); notFoundExt = false; break; } } } if (notFoundExt) { fileName += ".png"; } } string[] spli = fileName.Split('\\'); bool exists = false; string fname = ""; if (spli.Length > 0) { fileName = spli[spli.Length - 1]; if (File.Exists(this.DirectoryName + @"\" + fileName)) { fname = this.DirectoryName + @"\" + fileName; exists = true; } } if (!exists) { fname = fileName; exists = true; } this.materialNames.Add(materialID); this.materialFileNames.Add(fname); } } var wrapnode = this.Document.SelectNodes("//technique[@profile='MAYA']"); bool wrapUV = wrapnode != null && wrapnode.Count > 0; XmlNodeList geometries = this.Document.SelectNodes("//library_geometries/geometry"); for (int i = 0; i < geometries.Count; i++) { XmlNode mesh = geometries[i].SelectNodes("mesh")[0]; this.GeometryIDs.Add(geometries[i].SelectNodes("@id")[0].InnerText); XmlNodeList inputs = mesh.SelectNodes("*/input[@semantic]"); string vertexID = ""; string normalID = ""; string texcoordID = ""; string colorID = ""; vertexTriInd.Add(-1); normalTriInd.Add(-1); uvTriInd.Add(-1); colorTriInd.Add(-1); int stride = 0; for (int j = 0; j < inputs.Count; j++) { string semanticAtt = inputs[j].SelectNodes("@semantic")[0].InnerText.ToUpper(); XmlNodeList offsetAtt = inputs[j].SelectNodes("@offset"); switch (semanticAtt) { case "VERTEX": vertexTriInd[vertexTriInd.Count - 1] = 0; if (offsetAtt != null && offsetAtt.Count > 0) { vertexTriInd[vertexTriInd.Count - 1] = int.Parse(offsetAtt[0].InnerText); stride++; } break; case "POSITION": vertexID = inputs[j].SelectNodes("@source")[0].InnerText.Remove(0, 1); break; case "NORMAL": normalTriInd[normalTriInd.Count - 1] = 0; if (offsetAtt != null && offsetAtt.Count > 0) { normalTriInd[normalTriInd.Count - 1] = int.Parse(offsetAtt[0].InnerText); stride++; } normalID = inputs[j].SelectNodes("@source")[0].InnerText.Remove(0, 1); break; case "TEXCOORD": uvTriInd[uvTriInd.Count - 1] = 0; if (offsetAtt != null && offsetAtt.Count > 0) { uvTriInd[uvTriInd.Count - 1] = int.Parse(offsetAtt[0].InnerText); stride++; } texcoordID = inputs[j].SelectNodes("@source")[0].InnerText.Remove(0, 1); break; case "COLOR": colorTriInd[colorTriInd.Count - 1] = 0; if (offsetAtt != null && offsetAtt.Count > 0) { colorTriInd[colorTriInd.Count - 1] = int.Parse(offsetAtt[0].InnerText); stride++; } colorID = inputs[j].SelectNodes("@source")[0].InnerText.Remove(0, 1); break; } } if (vertexID.Length == 0) { throw new Exception("Error: Mesh " + i + " does not have vertices. Remove this mesh before to use this tool."); } string[] vertexArray = new string[0]; string[] normalArray = new string[0]; string[] texcoordArray = new string[0]; string[] colorArray = new string[0]; if (vertexID.Length > 0) { vertexArray = Format(mesh.SelectNodes(@"source[@id='" + vertexID + "']/float_array")[0].InnerText).Split(' '); } if (normalID.Length > 0) { normalArray = Format(mesh.SelectNodes(@"source[@id='" + normalID + "']/float_array")[0].InnerText).Split(' '); } if (texcoordID.Length > 0) { texcoordArray = Format(mesh.SelectNodes(@"source[@id='" + texcoordID + "']/float_array")[0].InnerText).Split(' '); } if (colorID.Length > 0) { colorArray = Format(mesh.SelectNodes(@"source[@id='" + colorID + "']/float_array")[0].InnerText).Split(' '); } this.Vertices.Add(new List <Vector3>(0)); this.Normal.Add(new List <Vector3>(0)); this.TextureCoordinates.Add(new List <Vector2>(0)); this.VertexColor.Add(new List <byte[]>(0)); this.Triangle.Add(new List <int[]>(0)); this.Influences.Add(new List <List <float> >(0)); this.InfluencesIndices.Add(new List <List <int> >(0)); for (int j = 0; j < vertexArray.Length; j += 3) { float x = Single.Parse(vertexArray[j]); float y = Single.Parse(vertexArray[j + 1]); float z = Single.Parse(vertexArray[j + 2]); if (x > this.MaxCoords.X) { this.MaxCoords.X = x; } if (x < this.MinCoords.X) { this.MinCoords.X = x; } if (y > this.MaxCoords.Y) { this.MaxCoords.Y = y; } if (y < this.MinCoords.Y) { this.MinCoords.Y = y; } if (z > this.MaxCoords.Z) { this.MaxCoords.Z = z; } if (z < this.MinCoords.Z) { this.MinCoords.Z = z; } this.Vertices.Last().Add(new Vector3(x, y, z)); } for (int j = 0; j < normalArray.Length; j += 3) { this.Normal.Last().Add(new Vector3(Single.Parse(normalArray[j]), Single.Parse(normalArray[j + 1]), Single.Parse(normalArray[j + 2]))); } for (int j = 0; j < texcoordArray.Length; j += 2) { Vector2 uv = new Vector2(Single.Parse(texcoordArray[j]), 1 - Single.Parse(texcoordArray[j + 1])); this.TextureCoordinates.Last().Add(uv); } for (int j = 0; j < colorArray.Length; j += 4) { this.VertexColor.Last().Add(new byte[] { (byte)(Single.Parse(colorArray[j]) * 128), (byte)(Single.Parse(colorArray[j + 1]) * 128), (byte)(Single.Parse(colorArray[j + 2]) * 128), (byte)(Single.Parse(colorArray[j + 3]) * 128) }); } string triangleString = mesh.SelectNodes(@"triangles/p")[0].InnerText; string[] triangleArray = Format(triangleString).Split(' '); for (int j = 0; j < triangleArray.Length; j += stride) { int[] indices = new int[stride]; for (int k = 0; k < stride; k++) { indices[k] = int.Parse(triangleArray[j + k]); } this.Triangle.Last().Add(indices); } } var bonesNode = this.Document.SelectNodes(@"//library_visual_scenes/visual_scene//node[@type='JOINT']"); // and not(contains(@name,'mesh')) if (bonesNode != null && bonesNode.Count > 0) { this.Skeleton.Bones = new Bone[bonesNode.Count]; this.Skeleton.BonesMatrices = new Matrix[bonesNode.Count]; this.Skeleton.BonesReMatrices = new Matrix[bonesNode.Count]; bonesNode = this.Document.SelectNodes(@"//library_visual_scenes/visual_scene/node[@type='JOINT']"); for (int i = 0; i < bonesNode.Count; i++) { XmlNode bone000 = bonesNode[i]; GetBoneNames(bone000); GetBones(bone000); UnwrapSkeleton(bone000, -1); } ComputeMatrices(); } XmlNodeList skinnings = this.Document.SelectNodes(@"//library_controllers/controller/skin"); for (int i = 0; i < skinnings.Count; i++) { var sourceNodes = skinnings[i].SelectNodes("@source"); if (sourceNodes == null || sourceNodes.Count == 0) { continue; } int geometryIndex = this.GeometryIDs.IndexOf(sourceNodes[0].InnerText.Remove(0, 1)); if (geometryIndex < 0) { continue; } string jointID = skinnings[i].SelectNodes(@"*/input[@semantic='JOINT']/@source")[0].InnerText.Remove(0, 1); string[] jointsArray = Format(skinnings[i].SelectNodes(@"source[@id='" + jointID + "']/Name_array")[0].InnerText).Split(' '); string[] skinCounts = Format(skinnings[i].SelectNodes(@"vertex_weights/vcount")[0].InnerText).Split(' '); string[] skins = Format(skinnings[i].SelectNodes(@"vertex_weights/v")[0].InnerText).Split(' '); string[] skinsWeights = Format(skinnings[i].SelectNodes(@"source[contains(@id, 'eights')]/float_array")[0].InnerText).Split(' '); int tabIndex = 0; for (int j = 0; j < skinCounts.Length; j++) { int influenceCount = int.Parse(skinCounts[j]); this.Influences[geometryIndex].Add(new List <float>(0)); this.InfluencesIndices[geometryIndex].Add(new List <int>(0)); for (int k = 0; k < influenceCount; k++) { int jointIndex = int.Parse(skins[tabIndex]); int weightIndex = int.Parse(skins[tabIndex + 1]); float weight = Single.Parse(skinsWeights[weightIndex]); string jointName = jointsArray[jointIndex]; this.Influences[geometryIndex].Last().Add(weight); this.InfluencesIndices[geometryIndex].Last().Add(BoneNames.IndexOf(jointName)); tabIndex += 2; } } } List <string> materialsFnames = new List <string>(0); for (int i = 0; i < this.Triangle.Count; i++) { string currController = ""; for (int l = 0; l < skinnings.Count; l++) { var node = skinnings[l].SelectNodes("@source"); if (node != null && node.Count > 0 && node[0].InnerText == "#" + this.GeometryIDs[i]) { node = skinnings[l].ParentNode.SelectNodes("@id"); if (node != null && node.Count > 0) { currController = node[0].InnerText; break; } } } string matID = ""; if (matID.Length == 0) { XmlNodeList instanceGeometry = this.Document.SelectNodes("//library_visual_scenes/visual_scene/node/instance_geometry[@url='#" + GeometryIDs[i] + "']//instance_material/@target"); if (instanceGeometry != null && instanceGeometry.Count > 0) { matID = instanceGeometry[0].InnerText.Remove(0, 1); if (!materialNames.Contains(matID)) { matID = ""; } } } if (matID.Length == 0) { XmlNodeList instanceController = this.Document.SelectNodes("//library_visual_scenes/visual_scene/node/instance_controller[@url='#" + currController + "']//instance_material/@target"); if (instanceController != null && instanceController.Count > 0) { matID = instanceController[0].InnerText.Remove(0, 1); if (!materialNames.Contains(matID)) { matID = ""; } } } if (matID.Length > 0) { string fname = materialFileNames[materialNames.IndexOf(matID)]; int mmaterialIndex = materialsFnames.Count; if (!materialsFnames.Contains(fname)) { materialsFnames.Add(fname); } else { mmaterialIndex = materialsFnames.IndexOf(fname); } MaterialIndices.Add(mmaterialIndex); } } this.RenderBuffer = new VertexPositionColorTexture[this.Triangle.Count][]; for (int i = 0; i < this.RenderBuffer.Length; i++) { this.RenderBuffer[i] = new VertexPositionColorTexture[this.Triangle[i].Count]; for (int j = 0; j < this.RenderBuffer[i].Length; j++) { this.RenderBuffer[i][j] = new VertexPositionColorTexture(); } } }