using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Text.RegularExpressions; using System.Drawing; using System.Globalization; namespace sharpgl { public class Section { public Section Parent { get; set; } public string Type { get; set; } public string[] Tokens { get; set; } public List Lines { get; set; } public string Text { get; set; } public Dictionary Values { get; set; } public List
Children { get; set; } public Section() { Lines = new List(); Values = new Dictionary(); Children = new List
(); } public static Section Parse() { return new Section(); } } public class TextureVertex : Point2D { } public class Vertex : Point3D { } public class Normal : Point3D { } public class Point2D { public float x; public float y; } public class Point3D { public float x; public float y; public float z; } public class Triangle { public int[] Vertices; public Triangle() { Vertices = new int[3]; } } public class Shape { public Vertex[] Vertices { get; set; } public Normal[] Normals { get; set; } public TextureVertex[] TextureVertices { get; set; } public Triangle[] Triangles { get; set; } public int MaterialId { get; set; } } public class Texture { public string Image; public int ReplaceableId; public int TextureName; // OpenGL texture name } public class Layer { public enum FilterModeType { None, Transparent, Blend } public FilterModeType FilterMode { get; set; } public int TextureId { get; set; } public bool Unshaded { get; set; } public string[] Alpha { get; set; } } public class Material { public List Layers; public Material() { Layers = new List(); } } public class MDLFile { public string Filename { get; set; } public int Version { get; set; } public List Shapes { get; set; } public Texture[] Textures { get; set; } public Material[] Materials { get; set; } public MDLFile(string filename) { this.Filename = filename; Shapes = new List(); } public void Parse() { string file = string.Empty; using (StreamReader reader = new StreamReader(Filename)) { file = reader.ReadToEnd(); } string[] lines = file.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries); List
sections = new List
(); for (int i = 0; i < lines.Length; i++) { string line = lines[i]; line = line.Trim(); // Comment if (string.IsNullOrWhiteSpace(line) || line.StartsWith("//")) { continue; } // New section else if (line.Contains("{") && !line.Contains(",")) { Section section = ParseSection(lines, ref i); sections.Add(section); } else { Debug.Write("Unmanaged line"); Debugger.Break(); } } foreach (Section section in sections) { switch (section.Type) { case "Version": Version = int.Parse((string)section.Values["FormatVersion"]); break; case "Textures": int ntextures = int.Parse(section.Tokens[1]); Textures = new Texture[ntextures]; for (int i = 0; i < ntextures; i++) { Section childSection = section.Children[i]; Texture texture = new Texture(); Textures[i] = texture; if (childSection.Values.ContainsKey("ReplaceableId")) { texture.ReplaceableId = int.Parse((string)childSection.Values["ReplaceableId"]); } texture.Image = (string)childSection.Values["Image"]; texture.Image = texture.Image.Replace("\"", ""); texture.Image = texture.Image.Replace(".blp", ".png"); if (!string.IsNullOrWhiteSpace(texture.Image)) { texture.Image = "../../" + texture.Image; OpenGLForm.GenerateTexture(texture); } //if (i == 0) break; } break; case "Materials": int nmaterials = int.Parse(section.Tokens[1]); Materials = new Material[nmaterials]; for (int i = 0; i < nmaterials; i++) { Section childSection = section.Children[i]; Material material = new Material(); Materials[i] = material; foreach (Section subSection in childSection.Children) { if (subSection.Type == "Layer") { Layer layer = new Layer(); material.Layers.Add(layer); layer.FilterMode = (Layer.FilterModeType)Enum.Parse(typeof(Layer.FilterModeType), (string)subSection.Values["FilterMode"]); layer.TextureId = int.Parse(((string)subSection.Values["TextureID"])); } } } break; case "Geoset": Shape shape = new Shape(); Shapes.Add(shape); shape.MaterialId = int.Parse((string)section.Values["MaterialID"]); foreach (Section childSection in section.Children) { if (childSection.Type == "Vertices") { int nvertices = int.Parse(childSection.Tokens[1]); shape.Vertices = new Vertex[nvertices]; for (int i = 0; i < nvertices; i++) { string value = (string)childSection.Values[i.ToString()]; value = value.Substring(1); value = value.Substring(0, value.Length - 2).Trim(); string[] coordinates = value.Split(new char[] { ',' }); Vertex vertex = new Vertex() { x = float.Parse(coordinates[0].Trim(), CultureInfo.InvariantCulture), y = float.Parse(coordinates[1].Trim(), CultureInfo.InvariantCulture), z = float.Parse(coordinates[2].Trim(), CultureInfo.InvariantCulture) }; shape.Vertices[i] = vertex; } } else if (childSection.Type == "Normals") { int nnormals = int.Parse(childSection.Tokens[1]); shape.Normals = new Normal[nnormals]; for (int i = 0; i < nnormals; i++) { string value = (string)childSection.Values[i.ToString()]; value = value.Substring(1); value = value.Substring(0, value.Length - 2).Trim(); string[] coordinates = value.Split(new char[] { ',' }); Normal normal = new Normal() { x = float.Parse(coordinates[0].Trim(), CultureInfo.InvariantCulture), y = float.Parse(coordinates[1].Trim(), CultureInfo.InvariantCulture), z = float.Parse(coordinates[2].Trim(), CultureInfo.InvariantCulture) }; shape.Normals[i] = normal; } } else if (childSection.Type == "TVertices") { int ntvertices = int.Parse(childSection.Tokens[1]); shape.TextureVertices = new TextureVertex[ntvertices]; for (int i = 0; i < ntvertices; i++) { string value = (string)childSection.Values[i.ToString()]; value = value.Substring(1); value = value.Substring(0, value.Length - 2).Trim(); string[] coordinates = value.Split(new char[] { ',' }); TextureVertex textureVertex = new TextureVertex() { x = float.Parse(coordinates[0].Trim(), CultureInfo.InvariantCulture), y = float.Parse(coordinates[1].Trim(), CultureInfo.InvariantCulture) }; shape.TextureVertices[i] = textureVertex; } } else if (childSection.Type == "Faces") { int n = int.Parse(childSection.Tokens[2]); foreach (Section subSection in childSection.Children) { if (subSection.Type == "Triangles") { shape.Triangles = new Triangle[n]; string value = (string)subSection.Values["0"]; value = value.Substring(1); value = value.Substring(0, value.Length - 2).Trim(); string[] indexes = value.Split(new char[] { ',' }); for (int i = 0; i < n / 3; i++) { Triangle triangle = new Triangle(); triangle.Vertices[0] = int.Parse(indexes[3 * i]); triangle.Vertices[1] = int.Parse(indexes[3 * i + 1]); triangle.Vertices[2] = int.Parse(indexes[3 * i + 2]); shape.Triangles[i] = triangle; } } } } } break; } } //Debugger.Break(); } public Section ParseSection(string[] lines, ref int index) { Section section = new Section(); string line = lines[index]; line = line.Trim(); string[] tokens = Split(line.Substring(0, line.Length - 1).Trim()); section.Tokens = tokens; section.Type = tokens[0]; section.Lines.Add(line); int counter = 0; for (int i = index + 1; i < lines.Length; i++) { line = lines[i]; line = line.Trim(); section.Lines.Add(line); // Comment if (string.IsNullOrWhiteSpace(line) || line.StartsWith("//")) { continue; } // New section else if (line.Contains("{") && !line.Contains(",")) { Section childSection = ParseSection(lines, ref i); childSection.Parent = section; section.Children.Add(childSection); } // End section else if (line.Contains("}") && !line.Contains(",")) { Debug.Write(counter); counter = 0; break; } // Value else { if (line.Contains("static")) { line = line.Replace("static ", ""); } string key = string.Empty; if (line.StartsWith("{")) { section.Values[counter.ToString()] = line; counter++; } else if (line.Contains(" ")) { key = line.Substring(0, line.IndexOf(" ")); // Single value // Multiple value string value = line.Substring(line.IndexOf(" ")); value = value.Substring(0, value.Length - 1).Trim(); section.Values[key] = value; } // Flag else { key = line.Substring(0, line.Length - 1).Trim(); section.Values[key] = true; } //Debug.Write("Unmanaged line"); //Debugger.Break(); } index = i + 1; } return section; } //public bool Read() //{ // bool success = false; // string file = string.Empty; // using (StreamReader reader = new StreamReader(Filename)) // { // file = reader.ReadToEnd(); // } // string[] lines = file.Split(new char[] { '\r', '\n' }); // int index = 0; // List
sections = ParseSections(lines, null, null, ref index); // Debug.Write(sections.Count); // foreach (Section section in sections) // { // switch (section.Type) // { // case "Version": // Version = int.Parse((string)section.Values["FormatVersion"]); // break; // } // } // return success; //} //public List
ParseSections(string[] lines, Section current, Section parent, ref int index) //{ // Section section = null; // int open = 0; // List
sections = new List
(); // //foreach (string line in lines) // //{ // for (int i = index; i < lines.Length; i++) // { // string line = lines[i]; // if (string.IsNullOrWhiteSpace(line) || line.StartsWith("//")) // { // continue; // } // // New section // if (section == null && line.Contains("{") && !line.Contains(",")) // { // //if (parent == null) // { // open++; // string[] tokens = Split(line.Substring(0, line.Length - 1).Trim()); // section = new Section() // { // Parent = parent, // Tokens = tokens, // Type = tokens[0] // }; // section.Text += line + Environment.NewLine; // } // //else // { // i++; // ParseSections(lines, section, section, ref i); // } // } // else if (section != null && line.Contains("{")) // { // if (!line.Contains("}")) // { // open++; // } // section.Lines.Add(line); // section.Text += line + Environment.NewLine; // } // else if (section != null && line.Contains(",")) // { // // Trim "," away // string value = line.Substring(0, line.Length - 1); // // Flag // if (!line.Contains(" ")) // { // string key = value.Trim(); // section.Values[key] = true; // } // else // { // string key = value.Substring(0, value.IndexOf(" ")).Trim(); // section.Values[key] = value.Substring(value.IndexOf(" ") + 1).Trim(); // } // } // else if (section != null && line.Contains("}")) // { // open--; // section.Text += line + Environment.NewLine; // //// End of value // //if (line.Contains("},")) // //{ // // if (open == 0) // // { // // section.Values["test"] = "test"; // // } // //} // //// End of section // //else // //{ // if (open == 0) // { // sections.Add(section); // section = null; // } // //} // } // else // { // section.Lines.Add(line); // section.Text += line + Environment.NewLine; // } // } // return sections; //} //public int ParseIntValue( //Version { // FormatVersion 800, //} //private void ReadVersion(StreamReader reader) //{ // string line; // while ((line = reader.ReadLine()) != null) // { // if (line.StartsWith("}")) // { // break; // } // string[] tokens = GetTokens(line); // Version = int.Parse(tokens[1]); // } //} //private string[] GetTokens(string line) //{ // line = line.Trim(); // if (line[line.Length - 1] == ',') // { // line = line.Substring(0, line.Length - 1); // } // string[] tokens = line.Split(new char[] { ' ' }); // for (int i = 0; i < tokens.Length; i++) // { // if (tokens[i].StartsWith("\"")) // { // tokens[i] = tokens[i].Substring(1, tokens[i].Length - 2); // } // } // return tokens; //} public string[] Split(string expression) { return Split(expression, " ", "\"", true); } public string[] Split(string expression, string delimiter, string qualifier, bool ignoreCase) { string _Statement = String.Format("{0}(?=(?:[^{1}]*{1}[^{1}]*{1})*(?![^{1}]*{1}))", Regex.Escape(delimiter), Regex.Escape(qualifier)); RegexOptions _Options = RegexOptions.Compiled | RegexOptions.Multiline; if (ignoreCase) _Options = _Options | RegexOptions.IgnoreCase; Regex _Expression = new Regex(_Statement, _Options); return _Expression.Split(expression); } } }