using System; using System.Collections.Generic; using System.Text; using Bind.Structures; using System.Diagnostics; namespace Bind.GL2 { class SpecReader : ISpecReader { #region --- ISpecReader Members --- #region public virtual DelegateCollection ReadDelegates(System.IO.StreamReader specFile) public virtual DelegateCollection ReadDelegates(System.IO.StreamReader specFile) { Console.WriteLine("Reading function specs."); //List delegates = new List(); DelegateCollection delegates = new DelegateCollection(); do { string line = NextValidLine(specFile); if (String.IsNullOrEmpty(line)) break; while (line.Contains("(") && !specFile.EndOfStream) { // Get next OpenGL function Bind.Structures.Delegate d = new Bind.Structures.Delegate(); // Get function name: d.Name = line.Split(Utilities.Separators, StringSplitOptions.RemoveEmptyEntries)[0]; if (d.Name == "CallLists") { } do { // Get function parameters and return value line = specFile.ReadLine(); List words = new List( line.Replace('\t', ' ').Split(Utilities.Separators, StringSplitOptions.RemoveEmptyEntries) ); if (words.Count == 0) break; // Identify line: switch (words[0]) { case "return": // Line denotes return value d.ReturnType.Type = words[1]; break; case "param": // Line denotes parameter Parameter p = new Parameter(); WrapperTypes wrapper; string type; p.Name = Utilities.Keywords.Contains(words[1]) ? "@" + words[1] : words[1]; p.Type = words[2]; p.Pointer = words[4] == "array" ? true : false; p.Flow = words[3] == "in" ? Parameter.FlowDirection.In : Parameter.FlowDirection.Out; d.Parameters.Add(p); break; // Version directive is not used. GetTexParameterIivEXT and GetTexParameterIuivEXT define two(!) versions (why?) //case "version": // Line denotes function version (i.e. 1.0, 1.2, 1.5) // d.UserData.Add("version", words[1]); // break; case "category": d.Category = words[1]; break; } } while (!specFile.EndOfStream); delegates.Add(d); } } while (!specFile.EndOfStream); return delegates; } #endregion #region public virtual EnumCollection ReadEnums(System.IO.StreamReader specFile) public virtual EnumCollection ReadEnums(System.IO.StreamReader specfile) { EnumCollection enums = new EnumCollection(); // complete_enum contains all opengl enumerants. Bind.Structures.Enum complete_enum = new Bind.Structures.Enum(); complete_enum.Name = "GLenum"; Trace.WriteLine(String.Format("Reading opengl enumerant specs")); Trace.Indent(); do { string line = NextValidLine(specfile); if (String.IsNullOrEmpty(line)) break; line = line.Replace('\t', ' '); // We just encountered the start of a new enumerant: while (!String.IsNullOrEmpty(line) && line.Contains("enum")) { string[] words = line.Split(Utilities.Separators, StringSplitOptions.RemoveEmptyEntries); if (words.Length == 0) continue; // Declare a new enumerant Bind.Structures.Enum e = new Bind.Structures.Enum(); e.Name = Char.IsDigit(words[0][0]) ? "GL_" + words[0] : words[0]; // And fill in the values for this enumerant do { line = NextValidLine(specfile); if (String.IsNullOrEmpty(line) || line.StartsWith("#")) continue; if (line.Contains("enum:") || specfile.EndOfStream) break; line = line.Replace('\t', ' '); words = line.Split(Utilities.Separators, StringSplitOptions.RemoveEmptyEntries); if (words.Length == 0) continue; // If we reach this point, we have found a new value for the current enumerant Constant c = new Constant(); if (line.Contains("=")) { // Trim the "GL_" from the start of the string. if (words[0].StartsWith("GL_")) words[0] = words[0].Substring(3); if (Char.IsDigit(words[0][0])) words[0] = "GL_" + words[0]; c.Name = words[0]; uint number; if (UInt32.TryParse(words[2].Replace("0x", String.Empty), System.Globalization.NumberStyles.AllowHexSpecifier, null, out number)) { // The value is a number, check if it should be unchecked. if (number > 0x7FFFFFFF) { c.Unchecked = true; } } else { // The value is not a number. // Strip the "GL_" from the start of the string. if (words[2].StartsWith("GL_")) words[2] = words[2].Substring(3); // If the name now starts with a digit (doesn't matter whether we // stripped "GL_" above), add a "GL_" prefix. // (e.g. GL_4_BYTES). if (Char.IsDigit(words[2][0])) words[2] = "GL_" + words[2]; } c.Value = words[2]; } else if (words[0] == "use") { // Trim the "GL_" from the start of the string. if (words[2].StartsWith("GL_")) words[2] = words[2].Substring(3); // If the remaining string starts with a digit, we were wrong above. // Re-add the "GL_" if (Char.IsDigit(words[2][0])) words[2] = "GL_" + words[2]; c.Name = words[2]; if (words[1] == "LightProperty") { Trace.WriteLine( String.Format( "Spec error: Enum LightProperty.{0} does no exist, changing to LightParameter.{0}", words[2] ) ); words[1] = "LightParameter"; } c.Reference = words[1]; c.Value = words[2]; } //if (!String.IsNullOrEmpty(c.Name) && !e.Members.Contains.Contains(c)) //SpecTranslator.Merge(e.Members, c); if (!e.ConstantCollection.ContainsKey(c.Name)) { e.ConstantCollection.Add(c.Name, c); } else { Trace.WriteLine( String.Format( "Spec error: Constant {0} defined twice in enum {1}, discarding last definition.", c.Name, e.Name ) ); } // Insert the current constant in the list of all constants. //SpecTranslator.Merge(complete_enum.Members, c); complete_enum = Utilities.Merge(complete_enum, c); } while (!specfile.EndOfStream); // At this point, the complete value list for the current enumerant has been read, so add this // enumerant to the list. //e.StartDirectives.Add(new CodeRegionDirective(CodeRegionMode.Start, "public enum " + e.Name)); //e.EndDirectives.Add(new CodeRegionDirective(CodeRegionMode.End, "public enum " + e.Name)); // (disabled) Hack - discard Boolean enum, it fsucks up the fragile translation code ahead. //if (!e.Name.Contains("Bool")) //Utilities.Merge(enums, e); if (!enums.ContainsKey(e.Name)) { enums.Add(e.Name, e); } else { // The enum already exists, merge constants. Trace.WriteLine(String.Format("Conflict: Enum {0} already exists, merging constants.", e.Name)); foreach (Constant t in e.ConstantCollection.Values) { Utilities.Merge(enums[e.Name], t); } } //enums.Add(e); } //SpecTranslator.Merge(enums, complete_enum); } while (!specfile.EndOfStream); enums.Add(complete_enum.Name, complete_enum); // Add missing enum { Trace.WriteLine("Spec error: SGIX_icc_texture enum missing, adding by hand."); Bind.Structures.Enum e = new Bind.Structures.Enum("SGIX_icc_texture"); e.ConstantCollection.Add("RGB_ICC_SGIX", new Constant("RGB_ICC_SGIX", "0x8460")); e.ConstantCollection.Add("RGBA_ICC_SGIX", new Constant("RGBA_ICC_SGIX", "0x8461")); e.ConstantCollection.Add("ALPHA_ICC_SGIX", new Constant("ALPHA_ICC_SGIX", "0x8462")); e.ConstantCollection.Add("LUMINANCE_ICC_SGIX", new Constant("LUMINANCE_ICC_SGIX", "0x8463")); e.ConstantCollection.Add("INTENSITY_ICC_SGIX", new Constant("INTENSITY_ICC_SGIX", "0x8464")); e.ConstantCollection.Add("LUMINANCE_ALPHA_ICC_SGIX", new Constant("LUMINANCE_ALPHA_ICC_SGIX", "0x8465")); e.ConstantCollection.Add("R5_G6_B5_ICC_SGIX", new Constant("R5_G6_B5_ICC_SGIX", "0x8466")); e.ConstantCollection.Add("R5_G6_B5_A8_ICC_SGIX", new Constant("R5_G6_B5_A8_ICC_SGIX", "0x8467")); e.ConstantCollection.Add("ALPHA16_ICC_SGIX", new Constant("ALPHA16_ICC_SGIX", "0x8468")); e.ConstantCollection.Add("LUMINANCE16_ICC_SGIX", new Constant("LUMINANCE16_ICC_SGIX", "0x8469")); e.ConstantCollection.Add("INTENSITY16_ICC_SGIX", new Constant("INTENSITY16_ICC_SGIX", "0x846A")); e.ConstantCollection.Add("LUMINANCE16_ALPHA8_ICC_SGIX", new Constant("LUMINANCE16_ALPHA8_ICC_SGIX", "0x846B")); enums.Add(e.Name, e); } Trace.Unindent(); return enums; } #endregion #region public virtual Dictionary ReadTypeMap(System.IO.StreamReader sr) public virtual Dictionary ReadTypeMap(System.IO.StreamReader sr) { Console.WriteLine("Reading opengl types."); Dictionary GLTypes = new Dictionary(); do { string line = sr.ReadLine(); if (String.IsNullOrEmpty(line) || line.StartsWith("#")) continue; string[] words = line.Split(new char[] { ' ', ',', '*', '\t' }, StringSplitOptions.RemoveEmptyEntries); if (words[0].ToLower() == "void") { // Special case for "void" -> "". We make it "void" -> "void" GLTypes.Add(words[0], "void"); } else if (words[0] == "VoidPointer" || words[0] == "ConstVoidPointer") { // "(Const)VoidPointer" -> "void*" GLTypes.Add(words[0], "void*"); } /*else if (words[0] == "CharPointer" || words[0] == "charPointerARB") { GLTypes.Add(words[0], "System.String"); } else if (words[0].Contains("Pointer")) { GLTypes.Add(words[0], words[1].Replace("Pointer", "*")); }*/ else if (words[1].Contains("GLvoid")) { GLTypes.Add(words[0], "void"); } else { GLTypes.Add(words[0], words[1]); } } while (!sr.EndOfStream); return GLTypes; } #endregion #region public virtual Dictionary ReadCSTypeMap(System.IO.StreamReader sr) public virtual Dictionary ReadCSTypeMap(System.IO.StreamReader sr) { Dictionary CSTypes = new Dictionary(); Console.WriteLine("Reading C# types."); while (!sr.EndOfStream) { string line = sr.ReadLine(); if (String.IsNullOrEmpty(line) || line.StartsWith("#")) continue; string[] words = line.Split(" ,".ToCharArray(), StringSplitOptions.RemoveEmptyEntries); if (words.Length < 2) continue; CSTypes.Add(words[0], words[1]); } return CSTypes; } #endregion #endregion #region protected virtual string NextValidLine(StreamReader sr) protected virtual string NextValidLine(System.IO.StreamReader sr) { string line; do { if (sr.EndOfStream) return null; line = sr.ReadLine().Trim(); if (String.IsNullOrEmpty(line) || line.StartsWith("#") || // Disregard comments. line.StartsWith("passthru") || // Disregard passthru statements. line.StartsWith("required-props:") || line.StartsWith("param:") || line.StartsWith("dlflags:") || line.StartsWith("glxflags:") || line.StartsWith("vectorequiv:") || //line.StartsWith("category:") || line.StartsWith("version:") || line.StartsWith("glxsingle:") || line.StartsWith("glxropcode:") || line.StartsWith("glxvendorpriv:") || line.StartsWith("glsflags:") || line.StartsWith("glsopcode:") || line.StartsWith("glsalias:") || line.StartsWith("wglflags:") || line.StartsWith("extension:") || line.StartsWith("alias:") || line.StartsWith("offset:")) continue; return line; } while (true); } #endregion } }