diff --git a/Source/Bind/BindStreamWriter.cs b/Source/Bind/BindStreamWriter.cs new file mode 100644 index 00000000..32550cb6 --- /dev/null +++ b/Source/Bind/BindStreamWriter.cs @@ -0,0 +1,53 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.IO; +using Bind.Structures; + +namespace Bind +{ + class BindStreamWriter : StreamWriter + { + public BindStreamWriter(string file) + : base(file) + { + } + + private string indent = ""; + + public void Indent() + { + indent = " " + indent; + } + + public void Unindent() + { + if (!String.IsNullOrEmpty(indent)) + indent = indent.Substring(4); + } + + public override void Write(string value) + { + base.Write(indent + value); + } + + public override void WriteLine(string value) + { + base.WriteLine(indent + value); + } + + public void Write(Bind.Structures.Enum e) + { + StringBuilder sb = new StringBuilder(e.ToString()); + sb.Replace(System.Environment.NewLine, System.Environment.NewLine + indent); + Write(sb); + } + + public void Write(Bind.Structures.Function f) + { + StringBuilder sb = new StringBuilder(f.ToString()); + sb.Replace(System.Environment.NewLine, System.Environment.NewLine + indent); + Write(sb); + } + } +} diff --git a/Source/Bind/GL2/Generator.cs b/Source/Bind/GL2/Generator.cs new file mode 100644 index 00000000..7c3d6e0b --- /dev/null +++ b/Source/Bind/GL2/Generator.cs @@ -0,0 +1,352 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.IO; +using Bind.Structures; +using System.Diagnostics; + +namespace Bind.GL2 +{ + class Generator : IBind + { + private SpecReader specReader = new SpecReader(); + private SpecWriter specWriter = new SpecWriter(); + DelegateCollection delegates = new DelegateCollection(); + FunctionCollection wrappers = new FunctionCollection(); + //List enums = new List(); + EnumCollection enums = new EnumCollection(); + EnumCollection extEnums = new EnumCollection(); + Dictionary GLTypes = new Dictionary(); + Dictionary CSTypes = new Dictionary(); + + string specFolder; + + public Generator(string folder) + { + specFolder = folder; + } + + #region IBind Members + + /* + public ISpecReader SpecReader + { + get { return specReader; } + } + */ + + #region public void Process() + + public void Process() + { + // Read + using (StreamReader sr = Utilities.OpenSpecFile(Settings.InputPath, "gl2\\gl.tm")) + { + GLTypes = specReader.ReadTypeMap(sr); + } + using (StreamReader sr = Utilities.OpenSpecFile(Settings.InputPath, "gl2\\csharp.tm")) + { + CSTypes = specReader.ReadCSTypeMap(sr); + } + using (StreamReader sr = Utilities.OpenSpecFile(Settings.InputPath, "gl2\\gl.spec")) + { + delegates = specReader.ReadDelegates(sr); + } + using (StreamReader sr = Utilities.OpenSpecFile(Settings.InputPath, "gl2\\enum.spec")) + { + enums = specReader.ReadEnums(sr); + } + using (StreamReader sr = Utilities.OpenSpecFile(Settings.InputPath, "gl2\\enumext.spec")) + { + extEnums = specReader.ReadEnums(sr); + } + + // Merge all opengl enumerants in enums + foreach (Bind.Structures.Enum e in extEnums.Values) + { + //enums.Add(e.Name, e); + Utilities.Merge(enums, e); + } + + // Process enums and delegates - create wrappers. + this.Translate(); + + + // Write + using (BindStreamWriter sw = new BindStreamWriter(Path.Combine(Settings.OutputPath, "GLEnums.cs"))) + { + sw.WriteLine("namespace {0}", Settings.OutputNamespace); + sw.WriteLine("{"); + + sw.Indent(); + sw.WriteLine("public static partial class {0}", Settings.GLClass); + sw.WriteLine("{"); + + sw.Indent(); + specWriter.WriteEnums(sw, enums); + sw.Unindent(); + + sw.WriteLine("}"); + sw.Unindent(); + + sw.WriteLine("}"); + } + using (BindStreamWriter sw = new BindStreamWriter(Path.Combine(Settings.OutputPath, "GLDelegates.cs"))) + { + sw.WriteLine("namespace {0}", Settings.OutputNamespace); + sw.WriteLine("{"); + + sw.Indent(); + specWriter.WriteTypes(sw, CSTypes); + specWriter.WriteDelegates(sw, delegates); + sw.Unindent(); + + sw.WriteLine("}"); + } + using (BindStreamWriter sw = new BindStreamWriter(Path.Combine(Settings.OutputPath, "GLCore.cs"))) + { + sw.WriteLine("namespace {0}", Settings.OutputNamespace); + sw.WriteLine("{"); + + sw.Indent(); + specWriter.WriteTypes(sw, CSTypes); + specWriter.WriteImports(sw, delegates); + sw.Unindent(); + + sw.WriteLine("}"); + } + using (BindStreamWriter sw = new BindStreamWriter(Path.Combine(Settings.OutputPath, "GL.cs"))) + { + sw.WriteLine("namespace {0}", Settings.OutputNamespace); + sw.WriteLine("{"); + + sw.Indent(); + specWriter.WriteTypes(sw, CSTypes); + specWriter.WriteWrappers(sw, wrappers, CSTypes); + sw.Unindent(); + + sw.WriteLine("}"); + } + } + + #endregion + + #endregion + + #region private void Translate() + + private void Translate() + { + foreach (Bind.Structures.Enum e in enums.Values) + { + TranslateEnum(e); + } + + foreach (Bind.Structures.Delegate d in delegates.Values) + { + TranslateReturnType(d); + TranslateParameters(d); + //wrappers.AddRange(d.CreateWrappers()); + foreach (Function f in d.CreateWrappers(CSTypes)) + { + if (!f.CLSCompliant) + { + Function clsFunction = f.GetCLSCompliantFunction(CSTypes); + if (clsFunction.Parameters.ToString(true) != f.Parameters.ToString(true)) + wrappers.Add(clsFunction); + } + wrappers.Add(f); + } + } + } + + #endregion + + #region private void TranslateReturnType(Bind.Structures.Delegate d) + + /// + /// Translates the opengl return type to the equivalent C# type. + /// + /// The opengl function to translate. + /// + /// First, we use the official typemap (gl.tm) to get the correct type. + /// Then we override this, when it is: + /// 1) A string (we have to use Marshal.PtrToStringAnsi, to avoid heap corruption) + /// 2) An array (translates to IntPtr) + /// 3) A generic object or void* (translates to IntPtr) + /// 4) A GLenum (translates to int on Legacy.Tao or GL.Enums.GLenum otherwise). + /// Return types must always be CLS-compliant, because .Net does not support overloading on return types. + /// + private void TranslateReturnType(Bind.Structures.Delegate d) + { + if (GLTypes.ContainsKey(d.ReturnType.Type)) + { + d.ReturnType.Type = GLTypes[d.ReturnType.Type]; + } + + if (d.ReturnType.Type.ToLower().Contains("void") && d.ReturnType.Pointer) + { + d.ReturnType.WrapperType = WrapperTypes.GenericReturnType; + } + + if (d.ReturnType.Type == "GLstring") + { + d.ReturnType.Type = "System.IntPtr"; + d.ReturnType.WrapperType = WrapperTypes.StringReturnType; + } + + if (d.ReturnType.Type.ToLower().Contains("object")) + { + d.ReturnType.Type = "System.IntPtr"; + d.ReturnType.WrapperType |= WrapperTypes.GenericReturnType; + } + + if (d.ReturnType.Type == "GLenum") + { + if (Settings.Compatibility == Settings.Legacy.None) + d.ReturnType.Type = Settings.GLClass + ".Enums.GLenum"; + else + d.ReturnType.Type = "int"; + } + + if (d.ReturnType.Type.ToLower().Contains("bool") && Settings.Compatibility == Settings.Legacy.Tao) + { + d.ReturnType.Type = "int"; + } + + if (d.ReturnType.WrapperType != WrapperTypes.None) + { + d.NeedsWrapper = true; + } + + d.ReturnType.Type = d.ReturnType.GetCLSCompliantType(CSTypes); + } + + #endregion + + #region private void TranslateParameters(Bind.Structures.Delegate d) + + private void TranslateParameters(Bind.Structures.Delegate d) + { + string s; + Bind.Structures.Enum @enum; + + foreach (Parameter p in d.Parameters) + { + // Translate enum parameters + if (enums.TryGetValue(p.Type, out @enum) && @enum.Name != "GLenum") + { + if (Settings.Compatibility == Settings.Legacy.None) + p.Type = p.Type.Insert(0, Settings.GLClass + ".Enums."); + else + p.Type = "int"; + } + else if (GLTypes.TryGetValue(p.Type, out s)) + { + // Check if the parameter is a generic GLenum. If yes, + // check if a better match exists: + if (s.Contains("GLenum") && !String.IsNullOrEmpty(d.Category)) + { + if (Settings.Compatibility == Settings.Legacy.None) + { + // Better match: enum.Name == function.Category (e.g. GL_VERSION_1_1 etc) + if (enums.ContainsKey(d.Category)) + { + p.Type = Settings.GLClass + ".Enums." + d.Category; + } + else + { + p.Type = Settings.GLClass + ".Enums.GLenum"; + } + } + else + { + p.Type = "int"; + } + } + else + { + // This is not enum, default translation: + p.Type = s; + } + } + + // Translate pointer parameters + if (p.Pointer) + { + p.WrapperType = WrapperTypes.ArrayParameter; + + if (p.Type.ToLower().Contains("char") || p.Type.ToLower().Contains("string")) + { + // char* or string -> [In] String or [Out] StringBuilder + p.Type = + p.Flow == Parameter.FlowDirection.Out ? + "System.Text.StringBuilder" : + "System.String"; + + if (d.Name.Contains("ShaderSource")) + { + // Special case: these functions take a string[] + //p.IsPointer = true; + p.Array = 1; + } + + p.Pointer = false; + p.WrapperType = WrapperTypes.None; + } + else if (p.Type.ToLower().Contains("void")) + { + p.WrapperType = WrapperTypes.GenericParameter; + } + } + + // Check for LineStipple (should be unchecked) + if (p.Type.ToLower().Contains("ushort") && d.Name.Contains("LineStipple")) + { + p.WrapperType = WrapperTypes.UncheckedParameter; + } + + if (p.Type.ToLower().Contains("bool")) + { + p.WrapperType = WrapperTypes.BoolParameter; + } + + if (p.WrapperType != WrapperTypes.None) + { + d.NeedsWrapper = true; + } + } + } + + #endregion + + #region private void TranslateEnum(Bind.Structures.Enum e) + + private void TranslateEnum(Bind.Structures.Enum e) + { + + foreach (Constant c in e.ConstantCollection.Values) + { + // There are cases when a value is an aliased constant, with no enum specified. + // (e.g. FOG_COORD_ARRAY_TYPE = GL_FOG_COORDINATE_ARRAY_TYPE) + // In this case try searching all enums for the correct constant to alias (stupid opengl specs). + if (String.IsNullOrEmpty(c.Reference) && !Char.IsDigit(c.Value[0])) + { + foreach (Bind.Structures.Enum @enum in enums.Values) + { + // Skip generic GLenum + if (@enum.Name == "GLenum") + continue; + + if (@enum.ConstantCollection.ContainsKey(c.Value)) + { + c.Reference = @enum.Name; + } + } + } + } + } + + #endregion + } +} diff --git a/Source/Bind/GL2/SpecReader.cs b/Source/Bind/GL2/SpecReader.cs new file mode 100644 index 00000000..a161e67b --- /dev/null +++ b/Source/Bind/GL2/SpecReader.cs @@ -0,0 +1,410 @@ +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 + } +} diff --git a/Source/Bind/GL2/SpecWriter.cs b/Source/Bind/GL2/SpecWriter.cs new file mode 100644 index 00000000..20bf7440 --- /dev/null +++ b/Source/Bind/GL2/SpecWriter.cs @@ -0,0 +1,206 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Bind.Structures; +using System.Diagnostics; + +namespace Bind.GL2 +{ + class SpecWriter : ISpecWriter + { + #region --- ISpecWriter Members --- + + #region void WriteDelegates + + public void WriteDelegates(BindStreamWriter sw, DelegateCollection delegates) + { + Trace.WriteLine(String.Format("Writing delegates to {0}.{1}", Settings.OutputNamespace, Settings.DelegatesClass)); + + sw.WriteLine(); + sw.WriteLine("internal static class {0}", Settings.DelegatesClass); + sw.WriteLine("{"); + + sw.Indent(); + // Disable BeforeFieldInit + sw.WriteLine("static {0}()", Settings.DelegatesClass); + sw.WriteLine("{"); + //sw.Indent(); + //sw.WriteLine("{0}.ReloadFunctions();", Settings.GLClass); + //sw.Unindent(); + sw.WriteLine("}"); + sw.WriteLine(); + foreach (Bind.Structures.Delegate d in delegates.Values) + { + sw.WriteLine("[System.Security.SuppressUnmanagedCodeSecurity()]"); + sw.WriteLine("internal {0};", d.ToString()); + if (d.Extension == "Core") + { + sw.WriteLine( + "internal {0}static {1} gl{1} = ({1}){2}.{3}(\"gl{1}\", typeof({1})) ?? new {1}({4}.{1});", + d.Unsafe ? "unsafe " : "", + d.Name, + Settings.GLClass, + "GetDelegateForExtensionMethod", + Settings.ImportsClass); + } + else + { + sw.WriteLine( + "internal {0}static {1} gl{1} = ({1}){2}.{3}(\"gl{1}\", typeof({1}));", + d.Unsafe ? "unsafe " : "", + d.Name, + Settings.GLClass, + "GetDelegateForExtensionMethod"); + } + } + sw.Unindent(); + + sw.WriteLine("}"); + } + + #endregion + + #region void WriteImports + + public void WriteImports(BindStreamWriter sw, DelegateCollection delegates) + { + Trace.WriteLine(String.Format("Writing imports to {0}.{1}", Settings.OutputNamespace, Settings.ImportsClass)); + + sw.WriteLine(); + sw.WriteLine("internal static class {0}", Settings.ImportsClass); + sw.WriteLine("{"); + + sw.Indent(); + sw.WriteLine("static {0}() {1} {2}", Settings.ImportsClass, "{", "}"); // Disable BeforeFieldInit + sw.WriteLine(); + foreach (Bind.Structures.Delegate d in delegates.Values) + { + sw.WriteLine("[System.Security.SuppressUnmanagedCodeSecurity()]"); + sw.WriteLine( + "[System.Runtime.InteropServices.DllImport({0}.Library, EntryPoint = \"gl{1}\", ExactSpelling = true)]", + Settings.GLClass, + d.Name + ); + sw.WriteLine("internal extern static {0};", d.DeclarationString()); + } + sw.Unindent(); + + sw.WriteLine("}"); + } + + #endregion + + #region void WriteWrappers + + public void WriteWrappers(BindStreamWriter sw, FunctionCollection wrappers, Dictionary CSTypes) + { + Trace.WriteLine(String.Format("Writing wrappers to {0}.{1}", Settings.OutputNamespace, Settings.GLClass)); + + sw.WriteLine(); + sw.WriteLine("public static partial class {0}", Settings.GLClass); + sw.WriteLine("{"); + + sw.Indent(); + sw.WriteLine("static {0}() {1} {2}", Settings.GLClass, "{", "}"); // Disable BeforeFieldInit + sw.WriteLine(); + foreach (string key in wrappers.Keys) + { + if (Settings.Compatibility == Settings.Legacy.None && key != "Core") + { + sw.WriteLine("public static class {0}", key); + sw.WriteLine("{"); + sw.Indent(); + } + + foreach (Function f in wrappers[key]) + { + if (Settings.Compatibility != Settings.Legacy.Tao) + Utilities.StripGL2Extension(f); + + if (f.Name == "ActiveTexture") + { + } + + if (!f.CLSCompliant) + { + sw.WriteLine("[System.CLSCompliant(false)]"); + } + sw.WriteLine("public static "); + sw.Write(f); + sw.WriteLine(); + } + + if (Settings.Compatibility == Settings.Legacy.None && key != "Core") + { + sw.Unindent(); + sw.WriteLine("}"); + sw.WriteLine(); + } + } + sw.Unindent(); + sw.WriteLine("}"); + } + + #endregion + + #region void WriteTypes + + public void WriteTypes(BindStreamWriter sw, Dictionary CSTypes) + { + sw.WriteLine("using System;"); + sw.WriteLine(); + foreach (string s in CSTypes.Keys) + { + sw.WriteLine("using {0} = System.{1};", s, CSTypes[s]); + } + } + + #endregion + + #region void WriteEnums + + public void WriteEnums(BindStreamWriter sw, EnumCollection enums) + { + Trace.WriteLine(String.Format("Writing enums to {0}.{1}", Settings.OutputNamespace, Settings.GLClass)); + + if (Settings.Compatibility == Settings.Legacy.None) + { + sw.WriteLine("public class Enums"); + sw.WriteLine("{"); + + sw.Indent(); + foreach (Bind.Structures.Enum @enum in enums.Values) + { + sw.Write(@enum); + sw.WriteLine(); + } + sw.Unindent(); + + sw.WriteLine("}"); + } + else if (Settings.Compatibility == Settings.Legacy.Tao) + { + // Tao legacy mode: dump all enums as constants in GLClass. + foreach (Bind.Structures.Constant c in enums["GLenum"].ConstantCollection.Values) + { + // Print constants avoiding circular definitions + if (c.Name != c.Value) + { + sw.WriteLine(String.Format( + "public const int {0} = {2}((int){1});", + c.Name.StartsWith("GL_") ? c.Name : "GL_" + c.Name, + Char.IsDigit(c.Value[0]) ? c.Value : c.Value.StartsWith("GL_") ? c.Value : "GL_" + c.Value, + c.Unchecked ? "unchecked" : "")); + } + else + { + } + } + } + } + + #endregion + + #endregion + } +} diff --git a/Source/Bind/IBind.cs b/Source/Bind/IBind.cs new file mode 100644 index 00000000..b54a2bc3 --- /dev/null +++ b/Source/Bind/IBind.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Bind +{ + interface IBind + { + //ISpecReader SpecReader { get; } + void Process(); + } +} diff --git a/Source/Bind/ISpecReader.cs b/Source/Bind/ISpecReader.cs new file mode 100644 index 00000000..84f0bf9c --- /dev/null +++ b/Source/Bind/ISpecReader.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.IO; + +namespace Bind +{ + interface ISpecReader + { + Bind.Structures.DelegateCollection ReadDelegates(StreamReader specFile); + Bind.Structures.EnumCollection ReadEnums(StreamReader specFile); + Dictionary ReadTypeMap(StreamReader specFile); + Dictionary ReadCSTypeMap(StreamReader specFile); + } +} diff --git a/Source/Bind/ISpecWriter.cs b/Source/Bind/ISpecWriter.cs new file mode 100644 index 00000000..5198e819 --- /dev/null +++ b/Source/Bind/ISpecWriter.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.IO; +using Bind.Structures; + +namespace Bind +{ + interface ISpecWriter + { + void WriteDelegates(BindStreamWriter sw, DelegateCollection delegates); + void WriteWrappers(BindStreamWriter sw, FunctionCollection wrappers, Dictionary CSTypes); + void WriteEnums(BindStreamWriter sw, EnumCollection enums); + void WriteTypes(BindStreamWriter sw, Dictionary CSTypes); + } +} diff --git a/Source/Bind/Main.cs b/Source/Bind/Main.cs index 9b6ebb3b..cc9774b5 100644 --- a/Source/Bind/Main.cs +++ b/Source/Bind/Main.cs @@ -33,19 +33,40 @@ using System.Security.Permissions; using System.Threading; using System.Collections.Generic; using System.CodeDom; +using System.Diagnostics; -namespace OpenTK.OpenGL.Bind +namespace Bind { + enum GeneratorMode + { + GL2, + GL3, + Wgl, + Glx, + Glu + } + static class MainClass { + static GeneratorMode mode; + static void Main(string[] arguments) { + Debug.Listeners.Clear(); + Debug.Listeners.Add(new TextWriterTraceListener(Console.Out)); + Debug.AutoFlush = true; + Trace.Listeners.Clear(); + Trace.Listeners.Add(new TextWriterTraceListener(Console.Out)); + Trace.AutoFlush = true; + Console.WriteLine("OpenGL binding generator {0} for OpenTK.", System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString()); Console.WriteLine("For comments, bugs and suggestions visit http://opentk.sourceforge.net"); //Console.WriteLine(" - the OpenTK team ;-)"); Console.WriteLine(); + IBind bind; + #region Handle Arguments try @@ -66,14 +87,36 @@ namespace OpenTK.OpenGL.Bind Settings.InputPath = b[1]; break; case "out": - case "Properties.Bind.Default.OutputPath": + case "output": Settings.OutputPath = b[1]; break; + case "mode": + mode = + b[1].ToLower() == "gl2" ? GeneratorMode.GL2 : + b[1].ToLower() == "gl3" ? GeneratorMode.GL3 : GeneratorMode.GL2; + break; + case "namespace": + case "ns": + Settings.OutputNamespace = b[1]; + break; + case "gl": + Settings.GLClass = b[1]; + break; + case "glu": + Settings.GluClass = b[1]; + break; + case "legacy": + Settings.Compatibility = b[1].ToLower() == "tao" ? Settings.Legacy.Tao : Settings.Legacy.None; + Settings.OutputNamespace = "Tao.OpenGl"; + Settings.GLClass = "Gl"; + break; case "class": Settings.GLClass = b[1]; break; default: - throw new ArgumentException("Argument " + a + " not recognized. Use the '/?' switch for help."); + throw new ArgumentException( + String.Format("Argument {0} not recognized. Use the '/?' switch for help.", a) + ); } } } @@ -95,34 +138,36 @@ namespace OpenTK.OpenGL.Bind { long ticks = System.DateTime.Now.Ticks; - List functions; - List delegates; - CodeTypeDeclarationCollection enums; - CodeTypeDeclarationCollection enums2; + switch (mode) + { + case GeneratorMode.GL2: + bind = new Bind.GL2.Generator(Settings.InputPath); + break; - delegates = SpecReader.ReadFunctionSpecs("gl.spec"); - SpecReader.ReadEnumSpecs("enum.spec", out enums); - SpecReader.ReadEnumSpecs("enumext.spec", out enums2); - enums = SpecTranslator.Merge(enums, enums2); - enums = SpecTranslator.TranslateEnums(enums); + default: + throw new NotImplementedException(String.Format("Mode {0} not implemented.", mode)); + } - functions = SpecTranslator.TranslateDelegates(delegates, enums); - - // Generate the code - SpecWriter.Generate(delegates, functions, enums); + bind.Process(); ticks = System.DateTime.Now.Ticks - ticks; + Console.WriteLine(); Console.WriteLine("Bindings generated in {0} seconds.", ticks / (double)10000000.0); Console.WriteLine(); - Console.WriteLine("Press enter to continue..."); - Console.ReadLine(); + Console.WriteLine("Press any key to continue..."); + Console.ReadKey(true); } catch (SecurityException e) { Console.WriteLine("Security violation \"{0}\" in method \"{1}\".", e.Message, e.Method); Console.WriteLine("This application does not have permission to take the requested actions."); } + catch (NotImplementedException e) + { + Console.WriteLine(e.Message); + Console.WriteLine("The requested functionality is not implemented yet."); + } } } } diff --git a/Source/Bind/Properties/AssemblyInfo.cs b/Source/Bind/Properties/AssemblyInfo.cs index 6c4765cd..7c80cf7d 100644 --- a/Source/Bind/Properties/AssemblyInfo.cs +++ b/Source/Bind/Properties/AssemblyInfo.cs @@ -29,5 +29,5 @@ using System.Runtime.InteropServices; // Build Number // Revision // -[assembly: AssemblyVersion("0.9.1.0")] -[assembly: AssemblyFileVersion("0.9.1.0")] +[assembly: AssemblyVersion("0.9.5.1")] +[assembly: AssemblyFileVersion("0.9.5.1")] diff --git a/Source/Bind/Settings.cs b/Source/Bind/Settings.cs index 3e0f0c0f..0a316ddb 100644 --- a/Source/Bind/Settings.cs +++ b/Source/Bind/Settings.cs @@ -7,18 +7,25 @@ using System; using System.Collections.Generic; using System.Text; -namespace OpenTK.OpenGL.Bind +namespace Bind { static class Settings { - public static string InputPath = "..\\..\\..\\Source\\OpenGL\\Specifications"; - public static string OutputPath = "..\\..\\..\\Source\\OpenGL\\OpenGL\\Bindings"; + public static string InputPath = "..\\..\\..\\Source\\Bind\\Specifications"; + public static string OutputPath = "..\\..\\..\\Source\\OpenTK\\OpenGL\\Bindings"; public static string OutputNamespace = "OpenTK.OpenGL"; public static string GLClass = "GL"; + public static string DelegatesClass = "Delegates"; + public static string ImportsClass = "Imports"; public static string WglClass = "Wgl"; public static string GlxClass = "Glx"; public static string GluClass = "Glu"; + public static Legacy Compatibility = Legacy.None; - public static string GLFunctionPrepend = String.Empty; + public enum Legacy + { + None, + Tao, + } } } diff --git a/Source/Bind/SpecReader.cs b/Source/Bind/SpecReader.cs deleted file mode 100644 index 76680c0a..00000000 --- a/Source/Bind/SpecReader.cs +++ /dev/null @@ -1,433 +0,0 @@ -#region --- License --- -/* -MIT License -Copyright ©2006-2007 Tao Framework Team -http://www.taoframework.com -Copyright ©2005-2007 OpenTK -http://sourceforge.net/projects/opentk - -All rights reserved. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -*/ -#endregion License - -#region --- Using Directives --- - -using System; -using System.Collections.Generic; -using System.Text; -using System.IO; -using System.CodeDom; - -#endregion - -namespace OpenTK.OpenGL.Bind -{ - static class SpecReader - { - #region internal static string FilePath - internal static string FilePath - { - get - { - string filePath = Path.Combine("..", ".."); - string fileDirectory = Settings.InputPath; - string fileName = "gl.spec"; - - if (File.Exists(fileName)) - { - filePath = ""; - fileDirectory = ""; - } - else if (File.Exists(Path.Combine(fileDirectory, fileName))) - { - filePath = ""; - } - return Path.Combine(filePath, fileDirectory); - } - } - #endregion - - #region private static StreamReader OpenSpecFile(string file) - private static StreamReader OpenSpecFile(string file) - { - string path = Path.Combine(FilePath, file); - StreamReader sr; - - try - { - sr = new StreamReader(path); - } - catch (Exception e) - { - Console.WriteLine("Error opening spec file: {0}", path); - Console.WriteLine("Error: {0}", e.Message); - throw e; - } - - return sr; - } - #endregion - - #region private static bool IsExtension(string function_name) - private static bool IsExtension(string function_name) - { - return (function_name.EndsWith("ARB") || - function_name.EndsWith("EXT") || - function_name.EndsWith("ATI") || - function_name.EndsWith("NV") || - function_name.EndsWith("SUN") || - function_name.EndsWith("SUNX") || - function_name.EndsWith("SGI") || - function_name.EndsWith("SGIS") || - function_name.EndsWith("SGIX") || - function_name.EndsWith("MESA") || - function_name.EndsWith("3DFX") || - function_name.EndsWith("IBM") || - function_name.EndsWith("GREMEDY") || - function_name.EndsWith("HP") || - function_name.EndsWith("INTEL") || - function_name.EndsWith("PGI") || - function_name.EndsWith("INGR") || - function_name.EndsWith("APPLE") || - function_name.EndsWith("OML") || - function_name.EndsWith("I3D")); - } - #endregion - - #region private static string NextValidLine(StreamReader sr) - private static string NextValidLine(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 - - #region public static void ReadFunctionSpecs(string file, out List delegates, out List functions) - public static List ReadFunctionSpecs(string file) - { - StreamReader sr = OpenSpecFile(file); - Console.WriteLine("Reading function specs from file: {0}", file); - - List delegates = new List(); - - do - { - string line = NextValidLine(sr); - if (String.IsNullOrEmpty(line)) - break; - - // Get next OpenGL function - while (line.Contains("(") && !sr.EndOfStream) - { - CodeTypeDelegate d = new CodeTypeDelegate(); - d.Attributes = MemberAttributes.Static; - d.CustomAttributes.Add(new CodeAttributeDeclaration("System.Security.SuppressUnmanagedCodeSecurity")); - - // Get function name: - d.Name = line.Split(SpecTranslator.Separators, StringSplitOptions.RemoveEmptyEntries)[0]; - if (IsExtension(d.Name)) - { - d.UserData.Add("Extension", true); - } - else - { - d.UserData.Add("Extension", false); - } - - //d.StartDirectives.Add(new CodeRegionDirective(CodeRegionMode.Start, d.Name)); - //d.EndDirectives.Add(new CodeRegionDirective(CodeRegionMode.End, d.Name)); - - // Get function parameters and return value: - do - { - line = sr.ReadLine(); - List words = new List( - line.Replace('\t', ' ').Split(SpecTranslator.Separators, StringSplitOptions.RemoveEmptyEntries)); - - if (words.Count == 0) - break; - - // Identify line: - switch (words[0]) - { - case "return": // Line denotes return value - CodeTypeReference tr = new CodeTypeReference( - words[1] - ); - - //if (tr.BaseType == "GLvoid") - // tr.BaseType = "System.Void"; - - d.ReturnType = tr; - break; - - case "param": // Line denotes parameter - CodeParameterDeclarationExpression p = - new CodeParameterDeclarationExpression(); - p.Name = words[1]; - p.Type = new CodeTypeReference(words[2]); - p.Direction = words[3] == "in" ? FieldDirection.In : FieldDirection.Out; - if (words[3] != "in") - p.CustomAttributes.Add(new CodeAttributeDeclaration("In, Out")); - p.Type.ArrayRank = words[4] == "array" ? 1 : 0; - - 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.UserData.Add("Category", words[1]); - break; - } - } - while (!sr.EndOfStream); - - delegates.Add(d); - } - } - while (!sr.EndOfStream); - - return delegates; - } - - #endregion - - #region public static void ReadEnumSpecs(string file, out List enums) - public static void ReadEnumSpecs(string file, out CodeTypeDeclarationCollection enums) - { - enums = new CodeTypeDeclarationCollection(); - // comple_enum contains all opengl enumerants. - CodeTypeDeclaration complete_enum = new CodeTypeDeclaration(); - complete_enum.IsEnum = true; - complete_enum.Name = "GLenum"; - - StreamReader sr = OpenSpecFile(file); - Console.WriteLine("Reading constant specs from file: {0}", file); - - do - { - string line = NextValidLine(sr); - 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(SpecTranslator.Separators, StringSplitOptions.RemoveEmptyEntries); - if (words.Length == 0) - continue; - - // Declare a new enumerant - CodeTypeDeclaration e = new CodeTypeDeclaration(); - e.IsEnum = true; - e.Name = SpecTranslator.GetTranslatedEnum(words[0]); - //d.Attributes = MemberAttributes.Const | MemberAttributes.Public; - - // And fill in the values for this enumerant - do - { - line = NextValidLine(sr); - - if (String.IsNullOrEmpty(line) || line.StartsWith("#")) - continue; - - if (line.Contains("enum:") || sr.EndOfStream) - break; - - line = line.Replace('\t', ' '); - words = line.Split(SpecTranslator.Separators, StringSplitOptions.RemoveEmptyEntries); - - if (words.Length == 0) - continue; - - // If we reach this point, we have found a new value for the current enumerant - CodeMemberField c = new CodeMemberField(); - if (line.Contains("=")) - { - c.Name = SpecTranslator.GetTranslatedEnum(words[0]); - - uint number; - if (UInt32.TryParse(words[2].Replace("0x", String.Empty), System.Globalization.NumberStyles.AllowHexSpecifier, null, out number)) - { - if (number > 0x7FFFFFFF) - { - words[2] = "unchecked((Int32)" + words[2] + ")"; - } - } - else if (words[2].StartsWith("GL_")) - { - words[2] = words[2].Substring(3); - } - - //c.InitExpression = new CodeFieldReferenceExpression(null, words[2]); - //c.UserData.Add("InitExpression", " = " + words[2]); - c.UserData.Add("ObjectReference", null); - c.UserData.Add("FieldReference", words[2]); - } - else if (words[0] == "use") - { - c.Name = SpecTranslator.GetTranslatedEnum(words[2]); - - //c.InitExpression = new CodeFieldReferenceExpression(new CodeSnippetExpression(words[1]), SpecTranslator.GetTranslatedEnum(words[2])); - //c.UserData.Add("InitExpression", " = " + words[1] + "." + SpecTranslator.GetTranslatedEnum(words[2])); - c.UserData.Add("ObjectReference", words[1]); - c.UserData.Add("FieldReference", words[2]); - } - - //if (!String.IsNullOrEmpty(c.Name) && !e.Members.Contains.Contains(c)) - SpecTranslator.Merge(e.Members, c); - - // Insert the current constant in the list of all constants. - SpecTranslator.Merge(complete_enum.Members, c); - } - while (!sr.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")) - SpecTranslator.Merge(enums, e); - } - SpecTranslator.Merge(enums, complete_enum); - } - while (!sr.EndOfStream); - } - - #endregion - - #region public static bool ListContainsConstant(List enums, CodeMemberField c) - public static bool ListContainsConstant(List constants, CodeMemberField c) - { - foreach (CodeMemberField d in constants) - if (d.Name == c.Name) - return true; - return false; - } - #endregion - - #region public static Dictionary ReadTypeMap(string file) - public static Dictionary ReadTypeMap(string file) - { - Dictionary map = - new Dictionary(); - - string path = Path.Combine(FilePath, file); - StreamReader sr; - - try - { - sr = new StreamReader(path); - } - catch (Exception) - { - Console.WriteLine("Error opening typemap file: {0}", path); - return null; - } - Console.WriteLine("Reading typemaps from file: {0}", file); - - do - { - string line = sr.ReadLine(); - - if (String.IsNullOrEmpty(line) || line.StartsWith("#")) - continue; - - string[] words = line.Split(new char[] { ' ', ',', '*', '\t' }, StringSplitOptions.RemoveEmptyEntries); - - if (words[0] == "void") - { - // Special case for "void" -> "" - map.Add(words[0], new CodeTypeReference(String.Empty)); - } - else if (words[0] == "VoidPointer") - { // Special case for "VoidPointer" -> "GLvoid*" - map.Add(words[0], new CodeTypeReference("System.Object")); - } - else if (words[0] == "CharPointer" || words[0] == "charPointerARB") - { - map.Add(words[0], new CodeTypeReference("System.String")); - } - else if (words[0].Contains("Pointer")) - { - map.Add(words[0], new CodeTypeReference(words[1], 1)); - } - //else if (words[1].Contains("Boolean")) - //{ - // // Do not add this to the typemap! - //} - /*else if (words[1] == "GLenum") - { - // Do not throw away the type to generic GLenum. We want type checking! - }*/ - else - { - map.Add(words[0], new CodeTypeReference(words[1])); - } - } - while (!sr.EndOfStream); - - return map; - } - #endregion - } -} diff --git a/Source/Bind/SpecTranslator.cs b/Source/Bind/SpecTranslator.cs deleted file mode 100644 index c13e49d9..00000000 --- a/Source/Bind/SpecTranslator.cs +++ /dev/null @@ -1,937 +0,0 @@ -#region --- License --- -/* -MIT License -Copyright ©2006-2007 Tao Framework Team -http://www.taoframework.com -Copyright ©2005-2007 OpenTK -http://sourceforge.net/projects/opentk - -All rights reserved. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -*/ -#endregion License - -#region --- Using Directives --- - -using System; -using System.Collections.Generic; -using System.Text; -using System.Collections; -using System.CodeDom; - -#endregion - -namespace OpenTK.OpenGL.Bind -{ - #region WrapperTypes enum - - public enum WrapperTypes - { - /// - /// No wrapper needed. - /// - None, - /// - /// Function takes bool parameter - C uses Int for bools, so we have to marshal. - /// - BoolParameter, - /// - /// Function takes generic parameters - add ref/out generic and generic overloads. - /// - GenericParameter, - /// - /// Function takes arrays as parameters - add ref/out and ([Out]) array overloads. - /// - ArrayParameter, - /// - /// Function with bitmask parameters. Bitmask parameters map to UInt, but since we can only use signed - /// types (for CLS compliance), we must add the unchecked keyword. - /// Usually found in bitmasks - /// - UncheckedParameter, - /// - /// Function that takes (in/ref/out) a naked pointer as a parameter - we pass an IntPtr. - /// - PointerParameter, - /// - /// Function returns string - needs manual marshalling through IntPtr to prevent the managed GC - /// from freeing memory allocated on the unmanaged side (e.g. glGetString). - /// - StringReturnValue, - /// - /// Function returns a void pointer - maps to IntPtr, and the user has to manually marshal the type. - /// - GenericReturnValue, - /// - /// Function returns a typed pointer - we have to copy the data to an array to protect it from the GC. - /// - ArrayReturnValue - } - - #endregion - - static class SpecTranslator - { - #region static SpecTranslator() - // Do not remove! - forces BeforeFieldInit to false. - static SpecTranslator() - { - } - #endregion - - #region Fields and Properties - public static char[] Separators = { ' ', '\n', ',', '(', ')', ';', '#' }; - - #region GL types dictionary - - private static Dictionary _gl_types = SpecReader.ReadTypeMap("gl.tm"); - - public static Dictionary GLTypes - { - get { return SpecTranslator._gl_types; } - set { SpecTranslator._gl_types = value; } - } - - #endregion - - #region CS types dictionary - - private static Dictionary _cs_types = SpecReader.ReadTypeMap("csharp.tm"); - - public static Dictionary CSTypes - { - get { return SpecTranslator._cs_types; } - set { SpecTranslator._cs_types = value; } - } - - #endregion - - #region GLX types dictionary - - private static Dictionary _glx_types; - - public static Dictionary GLXTypes - { - get { return _glx_types; } - set { _glx_types = value; } - } - - #endregion - - #region WGL types dictionary - - private static Dictionary _wgl_types; - - public static Dictionary WGLTypes - { - get { return _wgl_types; } - set { _wgl_types = value; } - } - - #endregion - #endregion - - #region public static List TranslateDelegates(List delegates, CodeTypeDeclarationCollection enums) - public static List TranslateDelegates(List delegates, CodeTypeDeclarationCollection enums) - { - List functions = new List(); - foreach (CodeTypeDelegate d in delegates) - { - TranslateReturnValue(d); - TranslateParameters(d, enums); - functions.AddRange(CreateWrappers(d)); - } - - return functions; - } - #endregion - - #region private static void TranslateReturnValue(CodeTypeDelegate d) - private static void TranslateReturnValue(CodeTypeDelegate d) - { - CodeTypeReference s; - - if (d.ReturnType.BaseType == "void") - d.ReturnType.BaseType = "System.Void"; - - if (GLTypes.TryGetValue(d.ReturnType.BaseType, out s)) - d.ReturnType = s; - - if (d.ReturnType.BaseType == "GLstring") - { - d.ReturnType = new CodeTypeReference("IntPtr"); - d.ReturnType.UserData.Add("Wrapper", WrapperTypes.StringReturnValue); - } - - if (d.ReturnType.BaseType.ToLower().Contains("object")) - { - d.ReturnType.BaseType = "IntPtr"; - d.ReturnType.UserData.Add("Wrapper", WrapperTypes.GenericReturnValue); - d.ReturnType.ArrayRank = 0; - } - - if (d.ReturnType.BaseType == "GLenum") - { - d.ReturnType.BaseType = "Enums.GLenum"; - } - - if (d.ReturnType.UserData.Contains("Wrapper")) - { - d.UserData.Add("Wrapper", null); - } - } - #endregion - - #region private static void TranslateParameters(CodeTypeDelegate d) - private static void TranslateParameters(CodeTypeDelegate d, CodeTypeDeclarationCollection enums) - { - CodeTypeReference s; - - if (d.Name == "CreateShader") - { - } - - // Translate each parameter of the function while checking for needed wrappers: - foreach (CodeParameterDeclarationExpression p in d.Parameters) - { - if (Search(enums, p.Type.BaseType) && p.Type.BaseType != "GLenum") - { - // If there is a specific enumerant entry for this parameter, then take this. - p.Type.BaseType = "Enums." + p.Type.BaseType; - } - else if (GLTypes.TryGetValue(p.Type.BaseType, out s)) - { - if (s.BaseType == "GLenum" && d.UserData.Contains("Category")) - { - // If there isn't, try to see if any of the generic enumerants - // (category: VERSION_1_1 etc) match the needed name. - bool found = false; - foreach (CodeTypeDeclaration enumerant in enums) - { - if (enumerant.Name == (string)d.UserData["Category"]) - { - p.Type.BaseType = "Enums." + (string)d.UserData["Category"]; - found = true; - break; - } - } - - // If none match, then fall back to the global enum list. - if (!found) - { - p.Type.BaseType = "Enums.GLenum"; - } - } - else - { - p.Type.BaseType = s.BaseType; - } - } - - if (p.Type.ArrayRank == 0 && p.Type.BaseType.ToLower().Contains("enums.")) - { - // Do nothing - } - else if (p.Type.ArrayRank > 0 && p.Type.BaseType.Contains("char") || - p.Type.ArrayRank == 0 && p.Type.BaseType.ToLower().Contains("string")) - { - // GLchar[] parameters should become (in) string or (out) StringBuilder - if (p.Direction == FieldDirection.Out || p.Direction == FieldDirection.Ref) - p.Type = new CodeTypeReference("System.Text.StringBuilder"); - else - p.Type = new CodeTypeReference("System.String"); - } - else if (p.Type.ArrayRank > 0 && p.Type.BaseType.ToLower().Contains("string")) - { - // string parameters do not need special wrappers. We add this here - // to simplify the next if-statements. - // p.Type.ArrayRank = 0; - } - else if (p.Type.ArrayRank > 0) - { - // All other array parameters need wrappers (around IntPtr). - if (p.Type.BaseType.Contains("void") || p.Type.BaseType.Contains("Void")) - { - p.UserData.Add("Wrapper", WrapperTypes.GenericParameter); - } - else if (p.Type.BaseType.Contains("IntPtr")) - { - //p.UserData.Add("Wrapper", WrapperTypes.PointerParameter); - } - else - { - p.UserData.Add("Wrapper", WrapperTypes.ArrayParameter); - p.UserData.Add("OriginalType", new string(p.Type.BaseType.ToCharArray())); - } - - // We do not want an array of IntPtrs (IntPtr[]) - it is the IntPtr that points to the array. - p.Type = new CodeTypeReference(); - p.Type.BaseType = "System.IntPtr"; - p.Type.ArrayRank = 0; - p.UserData.Add("Flow", p.Direction); - // The same wrapper works for either in or out parameters. - //p.CustomAttributes.Add(new CodeAttributeDeclaration("In, Out")); - } - else if (p.Type.BaseType.Contains("ushort") && d.Name.Contains("LineStipple")) - { - // glLineStipple needs wrapper to allow large unsigned mask values. - p.UserData.Add("Wrapper", WrapperTypes.UncheckedParameter); - } - - - if (p.Type.BaseType.ToLower().Contains("boolean")) - { - p.Type.BaseType = "System.Boolean"; - //p.UserData.Add("Wrapper", WrapperTypes.BoolParameter); - p.CustomAttributes.Add( - new CodeAttributeDeclaration( - "MarshalAs", - new CodeAttributeArgument(new CodeSnippetExpression("UnmanagedType.Bool")) - ) - ); - } - - if (p.UserData.Contains("Wrapper") && !d.UserData.Contains("Wrapper")) - { - // If there is at least 1 parameter that needs wrappers, mark the funcction for wrapping. - d.UserData.Add("Wrapper", null); - } - - //p.Direction = FieldDirection.In; - } - } - #endregion - - #region private static bool Search(CodeTypeDeclarationCollection enums, string name) - - private static bool Search(CodeTypeDeclarationCollection enums, string name) - { - foreach (CodeTypeDeclaration enumerant in enums) - { - if (enumerant.Name == name) - { - return true; - } - } - - return false; - } - - #endregion - - #region private static List CreateWrappers(CodeTypeDelegate d) - private static List CreateWrappers(CodeTypeDelegate d) - { - List wrappers = new List(); - CodeMemberMethod f = new CodeMemberMethod(); - - // Check if a wrapper is needed: - if (!d.UserData.Contains("Wrapper")) - { - // If not, add just add a function that calls the delegate. - f = CreatePrototype(d); - - if (!f.ReturnType.BaseType.Contains("Void")) - f.Statements.Add(new CodeMethodReturnStatement(GenerateInvokeExpression(f))); - else - f.Statements.Add(GenerateInvokeExpression(f)); - - wrappers.Add(f); - } - else - { - // We have to add wrappers for all possible WrapperTypes. - - // First, check if the return type needs wrapping: - if (d.ReturnType.UserData.Contains("Wrapper")) - { - switch ((WrapperTypes)d.ReturnType.UserData["Wrapper"]) - { - // If the function returns a string (glGetString) we must manually marshal it - // using Marshal.PtrToStringXXX. Otherwise, the GC will try to free the memory - // used by the string, resulting in corruption (the memory belongs to the - // unmanaged boundary). - case WrapperTypes.StringReturnValue: - f = CreatePrototype(d); - f.ReturnType = new CodeTypeReference("System.String"); - - f.Statements.Add( - new CodeMethodReturnStatement( - new CodeMethodInvokeExpression( - new CodeTypeReferenceExpression("Marshal"), - "PtrToStringAnsi", - new CodeExpression[] { GenerateInvokeExpression(f) } - ) - ) - ); - - wrappers.Add(f); - break; - - // If the function returns a void* (GenericReturnValue), we'll have to return an IntPtr. - // The user will unfortunately need to marshal this IntPtr to a data type manually. - case WrapperTypes.GenericReturnValue: - f = CreatePrototype(d); - - if (!f.ReturnType.BaseType.Contains("Void")) - f.Statements.Add(new CodeMethodReturnStatement(GenerateInvokeExpression(f))); - else - f.Statements.Add(GenerateInvokeExpression(f)); - - wrappers.Add(f); - break; - } - } - - if (d.Name.Contains("LineStipple")) - { - // glLineStipple accepts a GLushort bitfield. Since GLushort is mapped to Int16, not UInt16 - // (for CLS compliance), we'll have to add the unchecked keyword. - f = CreatePrototype(d); - - CodeSnippetExpression e = - new CodeSnippetExpression("Delegates.glLineStipple(factor, unchecked((GLushort)pattern))"); - f.Statements.Add(e); - - wrappers.Add(f); - } - - WrapPointersMonsterFunctionMK2(String.IsNullOrEmpty(f.Name) ? CreatePrototype(d) : f, wrappers); - } - - return wrappers; - } - #endregion - - #region private static void WrapPointersMonsterFunctionMK2(CodeTypeDelegate d, List wrappers) - // This function needs some heavy refactoring. I'm ashamed I ever wrote it, but it works... - // What it does is this: it adds to the wrapper list all possible wrapper permutations - // for functions that have more than one IntPtr parameter. Example: - // "void Delegates.f(IntPtr p, IntPtr q)" where p and q are pointers to void arrays needs the following wrappers: - // "void f(IntPtr p, IntPtr q)" - // "void f(IntPtr p, object q)" - // "void f(object p, IntPtr q)" - // "void f(object p, object q)" - private static int count = 0; - private static void WrapPointersMonsterFunctionMK2(CodeMemberMethod f, List wrappers) - { - if (count == 0) - { - bool functionContainsIntPtrParameters = false; - // Check if there are any IntPtr parameters (we may have come here from a ReturnType wrapper - // such as glGetString, which contains no IntPtr parameters) - foreach (CodeParameterDeclarationExpression p in f.Parameters) - { - if (p.Type.BaseType.Contains("IntPtr")) - { - functionContainsIntPtrParameters = true; - break; - } - } - - if (functionContainsIntPtrParameters) - { - wrappers.Add(IntPtrToIntPtr(f)); - } - else - { - return; - } - } - - if (count >= 0 && count < f.Parameters.Count) - { - if (f.Parameters[count].UserData.Contains("Wrapper")) - { - //++count; - //WrapPointersMonsterFunctionMK2(d, wrappers); - //--count; - - if ((WrapperTypes)f.Parameters[count].UserData["Wrapper"] == WrapperTypes.ArrayParameter) - { - ++count; - WrapPointersMonsterFunctionMK2(f, wrappers); - --count; - - CodeMemberMethod w = IntPtrToArray(f, count); - wrappers.Add(w); - - ++count; - WrapPointersMonsterFunctionMK2(w, wrappers); - --count; - - w = IntPtrToReference(f, count); - wrappers.Add(w); - - ++count; - WrapPointersMonsterFunctionMK2(w, wrappers); - --count; - } - else if ((WrapperTypes)f.Parameters[count].UserData["Wrapper"] == WrapperTypes.GenericParameter) - { - ++count; - WrapPointersMonsterFunctionMK2(f, wrappers); - --count; - - CodeMemberMethod w = IntPtrToObject(f, count); - wrappers.Add(w); - - ++count; - WrapPointersMonsterFunctionMK2(w, wrappers); - --count; - } - } - else - { - ++count; - WrapPointersMonsterFunctionMK2(f, wrappers); - --count; - } - } - } - - #endregion - - #region private static CodeMemberMethod IntPtrToIntPtr(CodeMemberMethod f) - private static CodeMemberMethod IntPtrToIntPtr(CodeMemberMethod f) - { - CodeMemberMethod w = CreatePrototype(f); - if (!w.ReturnType.BaseType.Contains("Void")) - { - w.Statements.Add(new CodeMethodReturnStatement(GenerateInvokeExpression(w))); - } - else - { - w.Statements.Add(GenerateInvokeExpression(w)); - } - return w; - } - #endregion - - #region private static CodeMemberMethod IntPtrToObject(CodeMemberMethod f, int index) - private static CodeMemberMethod IntPtrToObject(CodeMemberMethod f, int index) - { - CodeMemberMethod w = CreatePrototype(f); - - CodeParameterDeclarationExpression newp = new CodeParameterDeclarationExpression(); - newp.Name = f.Parameters[index].Name; - newp.Type = new CodeTypeReference("System.Object"); - //if (newp.Flow == Parameter.FlowDirection.Out) - // newp.Flow = Parameter.FlowDirection.Undefined; - w.Parameters[index] = newp; - - // In the function body we should pin all objects in memory before calling the - // low-level function. - w.Statements.AddRange(GenerateInvokeExpressionWithPins(w)); - - return w; - } - #endregion - - #region private static CodeMemberMethod IntPtrToArray(CodeMemberMethod f, int index) - // IntPtr -> GL[...] wrapper. - private static CodeMemberMethod IntPtrToArray(CodeMemberMethod f, int index) - { - CodeMemberMethod w = CreatePrototype(f); - - // Search and replace IntPtr parameters with the known parameter types: - CodeParameterDeclarationExpression newp = new CodeParameterDeclarationExpression(); - newp.Name = f.Parameters[index].Name; - newp.Type.BaseType = (string)f.Parameters[index].UserData["OriginalType"]; - newp.Type.ArrayRank = 1; - w.Parameters[index] = newp; - - // In the function body we should pin all objects in memory before calling the - // low-level function. - w.Statements.AddRange(GenerateInvokeExpressionWithPins(w)); - - return w; - } - #endregion - - #region private static CodeMemberMethod IntPtrToReference(CodeMemberMethod f, int index) - /// - /// Obtain an IntPtr to the reference passed by the user. - /// - /// - /// - /// - private static CodeMemberMethod IntPtrToReference(CodeMemberMethod f, int index) - { - CodeMemberMethod w = CreatePrototype(f); - - // Search and replace IntPtr parameters with the known parameter types: - CodeParameterDeclarationExpression newp = new CodeParameterDeclarationExpression(); - newp.Name = f.Parameters[index].Name; - newp.Type.BaseType = (string)f.Parameters[index].UserData["OriginalType"]; - if (f.Parameters[index].UserData.Contains("Flow") && - (FieldDirection)f.Parameters[index].UserData["Flow"] == FieldDirection.Out) - newp.Direction = FieldDirection.Out; - else - newp.Direction = FieldDirection.Ref; - w.Parameters[index] = newp; - - // In the function body we should pin all objects in memory before calling the - // low-level function. - w.Statements.AddRange(GenerateInvokeExpressionWithPins(w)); - - return w; - } - #endregion - - #region private static CodeMemberMethod CreatePrototype(CodeTypeDelegate d) - private static CodeMemberMethod CreatePrototype(CodeTypeDelegate d) - { - CodeMemberMethod f = new CodeMemberMethod(); - - f.Name = Settings.GLFunctionPrepend + d.Name; - f.Parameters.AddRange(d.Parameters); - f.ReturnType = d.ReturnType; - f.Attributes = MemberAttributes.Static | MemberAttributes.Public; - - //f.StartDirectives.Add(new CodeRegionDirective(CodeRegionMode.Start, f.Name)); - //f.EndDirectives.Add(new CodeRegionDirective(CodeRegionMode.End, f.Name)); - - /*f.Comments.Add(new CodeCommentStatement("", true)); - f.Comments.Add(new CodeCommentStatement(" ", true)); - f.Comments.Add(new CodeCommentStatement("", true));*/ - - return f; - } - #endregion - - #region private static CodeMemberMethod CreatePrototype(CodeMemberMethod d) - private static CodeMemberMethod CreatePrototype(CodeMemberMethod d) - { - CodeMemberMethod f = new CodeMemberMethod(); - - f.Name = d.Name; - f.Parameters.AddRange(d.Parameters); - f.ReturnType = d.ReturnType; - f.Attributes = MemberAttributes.Static | MemberAttributes.Public; - - //f.StartDirectives.Add(new CodeRegionDirective(CodeRegionMode.Start, f.Name)); - //f.EndDirectives.Add(new CodeRegionDirective(CodeRegionMode.End, f.Name)); - - foreach (object key in d.UserData.Keys) - { - f.UserData.Add(key, d.UserData[key]); - } - - /*f.Comments.Add(new CodeCommentStatement("", true)); - f.Comments.Add(new CodeCommentStatement(" ", true)); - f.Comments.Add(new CodeCommentStatement("", true));*/ - - return f; - } - #endregion - - #region private static CodeExpression GenerateInvokeExpression(CodeMemberMethod f) - private static CodeExpression GenerateInvokeExpression(CodeMemberMethod f) - { - CodeVariableReferenceExpression[] parameters = new CodeVariableReferenceExpression[f.Parameters.Count]; - int i = 0; - foreach (CodeParameterDeclarationExpression p in f.Parameters) - { - parameters[i++] = new CodeVariableReferenceExpression(p.Name); - } - - return new CodeMethodInvokeExpression( - new CodeTypeReferenceExpression("Delegates"), - "gl" + f.Name, - parameters - ); - } - #endregion - - #region private static CodeStatementCollection GenerateInvokeExpressionWithPins(CodeMemberMethod f) - private static CodeStatementCollection GenerateInvokeExpressionWithPins(CodeMemberMethod f) - { - CodeVariableReferenceExpression[] parameters = new CodeVariableReferenceExpression[f.Parameters.Count]; - CodeTryCatchFinallyStatement m = new CodeTryCatchFinallyStatement(); - CodeStatementCollection statements = new CodeStatementCollection(); - - int h = 0; - int i = 0; - foreach (CodeParameterDeclarationExpression p in f.Parameters) - { - // Do manual marshalling for objects and arrays, but not strings. - if (p.Type.BaseType == "object" || p.Type.BaseType == "System.Object" || - (p.Type.ArrayRank > 0 && !p.Type.BaseType.ToLower().Contains("string")) || - ((p.Direction == FieldDirection.Ref || p.Direction == FieldDirection.Out) && - !p.Type.BaseType.ToLower().Contains("string"))) - { - if (p.Direction == FieldDirection.Out) - { - statements.Add( - new CodeAssignStatement( - new CodeVariableReferenceExpression(p.Name), - new CodeSnippetExpression("default(" + p.Type.BaseType + ")") - ) - ); - } - - // Pin the object and store the resulting GCHandle to h0, h1, ... - CodeVariableDeclarationStatement s = new CodeVariableDeclarationStatement(); - s.Type = new CodeTypeReference("GCHandle"); - s.Name = "h" + h; - s.InitExpression = - new CodeMethodInvokeExpression( - new CodeTypeReferenceExpression("GCHandle"), - "Alloc", - new CodeTypeReferenceExpression[] { - new CodeTypeReferenceExpression(p.Name), - new CodeTypeReferenceExpression("GCHandleType.Pinned") - } - ); - statements.Add(s); - - // Free the object using the h0, h1, ... variables - m.FinallyStatements.Add( - new CodeMethodInvokeExpression( - new CodeTypeReferenceExpression("h" + h), - "Free" - ) - ); - - // Add the h(n) variable to the list of parameters - parameters[i] = new CodeVariableReferenceExpression("h" + h + ".AddrOfPinnedObject()"); - - // Add an assignment statement: "variable_name = (variable_type)h(n).Target" for out parameters. - if (p.Direction == FieldDirection.Out) - { - m.TryStatements.Add( - new CodeAssignStatement( - new CodeVariableReferenceExpression(p.Name), - new CodeSnippetExpression("(" + p.Type.BaseType + ")h" + h + ".Target") - ) - ); - } - - h++; - } - else - { - // Add the normal paramater to the parameter list - parameters[i] = new CodeVariableReferenceExpression(p.Name); - } - i++; - } - - if (f.ReturnType.BaseType.Contains("Void")) - { - m.TryStatements.Insert(0, - new CodeExpressionStatement( - new CodeMethodInvokeExpression( - new CodeTypeReferenceExpression("Delegates"), - "gl" + f.Name, - parameters - ) - ) - ); - } - else - { - m.TryStatements.Insert(0, new CodeVariableDeclarationStatement(f.ReturnType, "retval")); - m.TryStatements.Insert(1, - new CodeAssignStatement( - new CodeVariableReferenceExpression("retval"), - new CodeMethodInvokeExpression( - new CodeTypeReferenceExpression("Delegates"), - "gl" + f.Name, - parameters - ) - ) - ); - - m.TryStatements.Add( - new CodeMethodReturnStatement(new CodeVariableReferenceExpression("retval")) - ); - } - - statements.Add(m); - - return statements; - } - #endregion - - #region public static CodeTypeDeclarationCollection Merge(CodeTypeDeclarationCollection list1, CodeTypeDeclarationCollection list2) - public static CodeTypeDeclarationCollection Merge(CodeTypeDeclarationCollection list1, CodeTypeDeclarationCollection list2) - { - foreach (CodeTypeDeclaration d in list2) - { - Merge(list1, d); - } - - return list1; - } - #endregion - - #region public static CodeTypeDeclarationCollection Merge(CodeTypeDeclarationCollection list, CodeTypeDeclaration item) - public static CodeTypeDeclarationCollection Merge(CodeTypeDeclarationCollection list, CodeTypeDeclaration item) - { - bool t_exists = false; - foreach (CodeTypeDeclaration d in list) - { - if (d.Name == item.Name) - { - t_exists = true; - foreach (CodeTypeMember m in item.Members) - { - Merge(d.Members, m); - } - } - } - - if (!t_exists) - { - list.Add(item); - } - - return list; - } - #endregion - - #region public static CodeTypeMemberCollection Merge(CodeTypeMemberCollection list, CodeTypeMember item) - public static CodeTypeMemberCollection Merge(CodeTypeMemberCollection list, CodeTypeMember item) - { - bool t_exists = false; - foreach (CodeTypeMember d in list) - { - if (d.Name == item.Name) - { - t_exists = true; - } - } - - if (!t_exists) - { - list.Add(item); - } - - return list; - } - #endregion - - #region public static CodeTypeDeclarationCollection TranslateEnums(CodeTypeDeclarationCollection enums) - public static CodeTypeDeclarationCollection TranslateEnums(CodeTypeDeclarationCollection enums) - { - // Add missing enums. - { - CodeTypeDeclaration e = new CodeTypeDeclaration("SGIX_icc_texture"); - e.IsEnum = true; - CodeMemberField c; - c = new CodeMemberField(); c.Name = "RGB_ICC_SGIX"; c.InitExpression = new CodeFieldReferenceExpression(null, "0x8460"); e.Members.Add(c); - c = new CodeMemberField(); c.Name = "RGBA_ICC_SGIX"; c.InitExpression = new CodeFieldReferenceExpression(null, "0x8461"); e.Members.Add(c); - c = new CodeMemberField(); c.Name = "ALPHA_ICC_SGIX"; c.InitExpression = new CodeFieldReferenceExpression(null, "0x8462"); e.Members.Add(c); - c = new CodeMemberField(); c.Name = "LUMINANCE_ICC_SGIX"; c.InitExpression = new CodeFieldReferenceExpression(null, "0x8463"); e.Members.Add(c); - c = new CodeMemberField(); c.Name = "INTENSITY_ICC_SGIX"; c.InitExpression = new CodeFieldReferenceExpression(null, "0x8464"); e.Members.Add(c); - c = new CodeMemberField(); c.Name = "LUMINANCE_ALPHA_ICC_SGIX"; c.InitExpression = new CodeFieldReferenceExpression(null, "0x8465"); e.Members.Add(c); - c = new CodeMemberField(); c.Name = "R5_G6_B5_ICC_SGIX"; c.InitExpression = new CodeFieldReferenceExpression(null, "0x8466"); e.Members.Add(c); - c = new CodeMemberField(); c.Name = "R5_G6_B5_A8_ICC_SGIX"; c.InitExpression = new CodeFieldReferenceExpression(null, "0x8467"); e.Members.Add(c); - c = new CodeMemberField(); c.Name = "ALPHA16_ICC_SGIX"; c.InitExpression = new CodeFieldReferenceExpression(null, "0x8468"); e.Members.Add(c); - c = new CodeMemberField(); c.Name = "LUMINANCE16_ICC_SGIX"; c.InitExpression = new CodeFieldReferenceExpression(null, "0x8469"); e.Members.Add(c); - c = new CodeMemberField(); c.Name = "INTENSITY16_ICC_SGIX"; c.InitExpression = new CodeFieldReferenceExpression(null, "0x846A"); e.Members.Add(c); - c = new CodeMemberField(); c.Name = "LUMINANCE16_ALPHA8_ICC_SGIX"; c.InitExpression = new CodeFieldReferenceExpression(null, "0x846B"); e.Members.Add(c); - - enums.Add(e); - } - - // Translate enums. - foreach (CodeTypeDeclaration e in enums) - { - if (Char.IsDigit(e.Name[0])) - e.Name = e.Name.Insert(0, "_"); - - if (e.Name == "Boolean") - continue; - - foreach (CodeMemberField c in e.Members) - { - // Prepend an '_' if the first letter is a number (e.g. 4_BYTES -> _4_BYTES) - if (Char.IsDigit(c.Name[0])) - c.Name = c.Name.Insert(0, "_"); - - if (c.UserData["FieldReference"] == null) - continue; - - c.UserData["ObjectReference"] = GetTranslatedEnum((string)c.UserData["ObjectReference"]); - c.UserData["FieldReference"] = GetTranslatedEnum((string)c.UserData["FieldReference"]); - - // There are cases when a value is not a number but an aliased constant, with no enum specified. - // In this case try searching all enums for the correct constant to alias (stupid opengl specs). - if (c.UserData["ObjectReference"] == null && - !((string)c.UserData["FieldReference"]).StartsWith("0x") && - !Char.IsDigit(((string)c.UserData["FieldReference"])[0])) - { - if (((string)c.UserData["FieldReference"]).StartsWith("GL_")) - c.UserData["FieldReference"] = ((string)c.UserData["FieldReference"]).Substring(3); - - foreach (CodeTypeDeclaration enumerant in enums) - { - foreach (CodeTypeMember member in enumerant.Members) - { - if (member.Name == (string)c.UserData["FieldReference"] || - member.Name == ((string)c.UserData["FieldReference"]).TrimStart('_')) - { - c.UserData["ObjectReference"] = enumerant.Name; - } - } - } - } - - c.InitExpression = - new CodeFieldReferenceExpression( - c.UserData["ObjectReference"] == null ? null : new CodeSnippetExpression((string)c.UserData["ObjectReference"]), - (string)c.UserData["FieldReference"] - ); - } - } - - return enums; - } - #endregion - - #region public static string GetTranslatedEnum(string name) - public static string GetTranslatedEnum(string name) - { - int useless; - - if (String.IsNullOrEmpty(name)) - return null; - - // Check if the name starts with a number, and prepend a "_" if yes. - if (!name.StartsWith("0x") && - !Int32.TryParse(name, out useless) && - Char.IsDigit(name[0])) - { - return name.Insert(0, "_"); - } - - if (name == "LightProperty") - { - return "LightParameter"; - } - - return name; - } - #endregion - } -} diff --git a/Source/Bind/SpecWriter.cs b/Source/Bind/SpecWriter.cs deleted file mode 100644 index d330463b..00000000 --- a/Source/Bind/SpecWriter.cs +++ /dev/null @@ -1,350 +0,0 @@ -#region --- License --- -/* -MIT License -Copyright ©2006-2007 Tao Framework Team -http://www.taoframework.com -Copyright ©2005-2007 OpenTK -http://sourceforge.net/projects/opentk - -All rights reserved. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -*/ -#endregion License - -#region --- Using Directives --- - -using System; -using System.Collections.Generic; -using System.Text; -using System.IO; -using System.Runtime.InteropServices; -using System.CodeDom; - -#endregion - -namespace OpenTK.OpenGL.Bind -{ - static class SpecWriter - { - #region internal class CodeTypeNameComparer : Comparer where T : CodeTypeMember - internal class CodeTypeNameComparer : Comparer where T : CodeTypeMember - { - public override int Compare(T x, T y) - { - return x.Name.CompareTo(y.Name); - } - } - #endregion - - #region Generate - - public static void Generate( - List delegates, - List functions, - CodeTypeDeclarationCollection enums - ) - { - if (!Directory.Exists(Settings.OutputPath)) - Directory.CreateDirectory(Settings.OutputPath); - - CodeNamespace ns = new CodeNamespace(Settings.OutputNamespace); - - ns.Imports.Add(new CodeNamespaceImport("System")); - ns.Imports.Add(new CodeNamespaceImport("System.Runtime.InteropServices")); - ns.Imports.Add(new CodeNamespaceImport("System.Text")); - //ns.Imports.Add(new CodeNamespaceImport(Settings.OutputNamespace + ".Enums")); - - foreach (string key in SpecTranslator.CSTypes.Keys) - { - ns.Imports.Add(new CodeNamespaceImport(key + " = System." + SpecTranslator.CSTypes[key].BaseType)); - } - - functions.Sort(new CodeTypeNameComparer()); - delegates.Sort(new CodeTypeNameComparer()); - - - ns.Types.Add(GenerateGLClass(functions)); - ns.Types.Add(GenerateDelegatesClass(delegates)); - ns.Types.Add(GenerateImportsClass(delegates)); - - CodeCompileUnit cu = new CodeCompileUnit(); - - cu.StartDirectives.Add(new CodeDirective()); - cu.Namespaces.Add(ns); - - using (StreamWriter sw = new StreamWriter(Path.Combine(Settings.OutputPath, Settings.GLClass + ".cs"), false)) - { - Console.WriteLine("Writing {0} class", Settings.OutputNamespace + "." + Settings.GLClass); - - Microsoft.CSharp.CSharpCodeProvider cs = new Microsoft.CSharp.CSharpCodeProvider(); - System.CodeDom.Compiler.CodeGeneratorOptions options = new System.CodeDom.Compiler.CodeGeneratorOptions(); - options.BracingStyle = "C"; - options.BlankLinesBetweenMembers = false; - options.VerbatimOrder = true; - - cs.GenerateCodeFromCompileUnit(cu, sw, options); - - sw.Flush(); - } - - ns.Name = Settings.OutputNamespace + ".Enums"; - ns.Imports.Clear(); - ns.Imports.Add(new CodeNamespaceImport("System")); - ns.Types.Clear(); - //enums.Sort(new CodeTypeNameComparer()); - //CodeTypeDeclaration d = new CodeTypeDeclaration("Enums"); - //d.IsStruct = true; - //d.Members.AddRange(enums); - //ns.Types.Add(d); - ns.Types.AddRange(enums); - - using (StreamWriter sw = new StreamWriter(Path.Combine(Settings.OutputPath, Settings.GLClass + "enums.cs"), false)) - { - Console.WriteLine("Writing {0} enums", Settings.OutputNamespace + "." + Settings.GLClass); - - Microsoft.CSharp.CSharpCodeProvider cs = new Microsoft.CSharp.CSharpCodeProvider(); - System.CodeDom.Compiler.CodeGeneratorOptions options = new System.CodeDom.Compiler.CodeGeneratorOptions(); - options.BracingStyle = "C"; - options.BlankLinesBetweenMembers = false; - options.VerbatimOrder = true; - - cs.GenerateCodeFromCompileUnit(cu, sw, options); - - sw.Flush(); - } - } - - #endregion - - #region private static CodeTypeDeclaration GenerateGLClass(List functions, List enums) - private static CodeTypeDeclaration GenerateGLClass(List functions) - { - CodeTypeDeclaration gl_class = new CodeTypeDeclaration(Settings.GLClass); - gl_class.IsClass = true; - gl_class.IsPartial = true; - gl_class.TypeAttributes = System.Reflection.TypeAttributes.Public; - - gl_class.StartDirectives.Add(new CodeRegionDirective(CodeRegionMode.Start, "GL class")); - gl_class.EndDirectives.Add(new CodeRegionDirective(CodeRegionMode.End, "GL class")); - - gl_class.Members.Add(new CodeSnippetTypeMember(" #pragma warning disable 1591")); - - gl_class.Members.Add(new CodeSnippetTypeMember( -@" - #region Private Constants - - #region string GL_NATIVE_LIBRARY - /// - /// Specifies OpenGl's native library archive. - /// - /// - /// Specifies opengl32.dll everywhere; will be mapped via .config for mono. - /// - internal const string GL_NATIVE_LIBRARY = ""opengl32.dll""; - #endregion string GL_NATIVE_LIBRARY - - #endregion Private Constants -")); - /* - if (constants.Count > 0) - { - constants[0].StartDirectives.Add(new CodeRegionDirective(CodeRegionMode.Start, "OpenGL constants")); - constants[constants.Count - 1].EndDirectives.Add(new CodeRegionDirective(CodeRegionMode.End, "OpenGL constants")); - } - gl_class.Members.AddRange(constants.ToArray()); - */ - if (functions.Count > 0) - { - functions[0].StartDirectives.Add(new CodeRegionDirective(CodeRegionMode.Start, "OpenGL functions")); - functions[functions.Count - 1].EndDirectives.Add(new CodeRegionDirective(CodeRegionMode.End, "OpenGL functions")); - } - gl_class.Members.AddRange(functions.ToArray()); - - return gl_class; - } - #endregion - - #region private static CodeTypeDeclaration GenerateDelegatesClass(List delegates) - private static CodeTypeDeclaration GenerateDelegatesClass(List delegates) - { - CodeTypeDeclaration delegate_class = new CodeTypeDeclaration("Delegates"); - delegate_class.TypeAttributes = System.Reflection.TypeAttributes.NotPublic; - - CodeStatementCollection statements = new CodeStatementCollection(); - - foreach (CodeTypeDelegate d in delegates) - { - // Hack - turn FieldDirection.Out parameters to FieldDirection.In. The parameter flow - // is handle by the [In, Out()] parameter attribute. - foreach (CodeParameterDeclarationExpression p in d.Parameters) - { - p.Direction = FieldDirection.In; - } - delegate_class.Members.Add(d); - - CodeMemberField m = new CodeMemberField(); - m.Name = "gl" + d.Name; - m.Type = new CodeTypeReference(d.Name); - m.Attributes = MemberAttributes.Public | MemberAttributes.Static; - - //m.InitExpression = - //new CodeCastExpression( - // "Delegates." + d.Name, - // new CodeMethodInvokeExpression( - // new CodeMethodReferenceExpression( - // new CodeTypeReferenceExpression(Properties.Bind.Default.OutputClass), - // "GetDelegateForExtensionMethod" - // ), - // new CodeExpression[] { - // new CodeSnippetExpression("\"gl" + d.Name + "\""), - // new CodeTypeOfExpression("Delegates." + d.Name) - // } - // ) - //); - - // Hack - generate inline initialisers in the form: - // public static Accum glAccum = GetDelegate[...] ?? new Accum(Imports.Accum); - CodeSnippetExpression expr = new CodeSnippetExpression(); - //expr.Value = "public static " + d.Name + " gl" + d.Name + " = "; - expr.Value += - "((" + d.Name + ")(" + Settings.GLClass +".GetDelegateForExtensionMethod(\"" + "gl" + d.Name + "\", typeof(" + d.Name + "))))"; - if (d.UserData.Contains("Extension") && !(bool)d.UserData["Extension"]) - { - expr.Value += " ?? "; - expr.Value += "new " + d.Name + "(Imports." + d.Name + ")"; - } - - m.InitExpression = expr; - delegate_class.Members.Add(m); - - /* - if (!(bool)d.UserData["Extension"]) - { - statements.Add( - new CodeSnippetExpression( - "Delegates.gl" + d.Name + " = Delegates.gl" + d.Name + " ?? new Delegates." + d.Name + "(Imports." + d.Name + ")" - ) - ); - } - */ - } - - // Disable BeforeFieldInit attribute and initialize OpenGL core. - CodeTypeConstructor con = new CodeTypeConstructor(); - //con.Statements.AddRange(statements); - delegate_class.Members.Add(con); - - delegate_class.StartDirectives.Add(new CodeRegionDirective(CodeRegionMode.Start, delegate_class.Name)); - delegate_class.EndDirectives.Add(new CodeRegionDirective(CodeRegionMode.End, delegate_class.Name)); - - return delegate_class; - } - #endregion - - #region private static CodeTypeDeclaration GenerateImportsClass(List delegates) - private static CodeTypeDeclaration GenerateImportsClass(List delegates) - { - CodeTypeDeclaration import_class = new CodeTypeDeclaration("Imports"); - import_class.TypeAttributes = System.Reflection.TypeAttributes.NotPublic; - import_class.Members.Add(new CodeTypeConstructor()); - - foreach (CodeTypeDelegate d in delegates) - { - if (!(bool)d.UserData["Extension"]) - { - CodeMemberMethodImport m = new CodeMemberMethodImport(); - - m.Name = d.Name; - m.CustomAttributes.Add(new CodeAttributeDeclaration("System.Security.SuppressUnmanagedCodeSecurity()")); - m.CustomAttributes.Add( - new CodeAttributeDeclaration( - "DllImport(" + Settings.GLClass + ".GL_NATIVE_LIBRARY, EntryPoint = \"" + "gl" + m.Name + "\", ExactSpelling = true)" - ) - ); - m.Parameters.AddRange(d.Parameters); - m.ReturnType = d.ReturnType; - - import_class.Members.Add(new CodeSnippetTypeMember(m.Text)); - - } - } - - import_class.StartDirectives.Add(new CodeRegionDirective(CodeRegionMode.Start, import_class.Name)); - import_class.EndDirectives.Add(new CodeRegionDirective(CodeRegionMode.End, import_class.Name)); - - return import_class; - } - #endregion - } - - #region class CodeMemberMethodImport : CodeMemberMethod - /// - /// A hack to create the C# code for a DllImported function; - /// CodeDom does not directly support static extern methods. - /// - class CodeMemberMethodImport : CodeMemberMethod - { - public string Text - { - get - { - string s; - //m.Attributes = MemberAttributes.Static | MemberAttributes.Public; - s = " #region " + this.Name + Environment.NewLine; - s += " [System.Security.SuppressUnmanagedCodeSecurity()]" + Environment.NewLine; - s += " [DllImport(" + Settings.GLClass + ".GL_NATIVE_LIBRARY, EntryPoint = \"" + "gl" + this.Name + "\", ExactSpelling = true)]" + Environment.NewLine; - s += " public extern static "; - if (this.ReturnType.BaseType == "System.Void") - { - s += "void"; - } - else - { - s += this.ReturnType.BaseType; - } - - s += " " + this.Name + "("; - foreach (CodeParameterDeclarationExpression p in this.Parameters) - { - s += p.Type.BaseType; - if (p.Type.ArrayRank > 0) - s += "[]"; - s += " "; - if (p.Name == "base") - s += "@base"; - else if (p.Name == "params") - s += "@params"; - else if (p.Name == "string") - s += "@string"; - else if (p.Name == "ref") - s += "@ref"; - else - s += p.Name; - s += ", "; - } - s = s.TrimEnd(',', ' ') + ");" + Environment.NewLine; - s += " #endregion" + Environment.NewLine; - - return s; - } - } - } - #endregion -} diff --git a/Source/Bind/Specifications/csharp.tm b/Source/Bind/Specifications/GL2/csharp.tm similarity index 58% rename from Source/Bind/Specifications/csharp.tm rename to Source/Bind/Specifications/GL2/csharp.tm index 88ac6d15..48278fe7 100644 --- a/Source/Bind/Specifications/csharp.tm +++ b/Source/Bind/Specifications/GL2/csharp.tm @@ -3,17 +3,17 @@ GLsizei, Int32 GLsizeiptr, IntPtr GLintptr, IntPtr # GLenum, Int32 -GLboolean, Boolean #Int32 #Boolean -GLbitfield, Int32 #UInt32 +GLboolean, Boolean #Int32 +GLbitfield, UInt32 # GLvoid*, IntPtr -GLvoid, Object +# GLvoid, Void #Object GLchar, Char -GLbyte, Byte #SByte +GLbyte, SByte GLubyte, Byte GLshort, Int16 -GLushort, Int16 #UInt16 +GLushort, UInt16 GLint, Int32 -GLuint, Int32 #UInt32 +GLuint, UInt32 GLfloat, Single GLclampf, Single GLdouble, Double @@ -23,13 +23,13 @@ GLstring, String # ARB and NV types. GLsizeiptrARB, IntPtr GLintptrARB, IntPtr -GLhandleARB, Int32 #UInt32 -GLhalfARB, Int16 #UInt16 -GLhalfNV, Int16 #UInt16 +GLhandleARB, UInt32 +GLhalfARB, UInt16 +GLhalfNV, UInt16 GLcharARB, Char # 64 bit types (introduced in 2.1) GLint64EXT, Int64 -GLuint64EXT, Int64 +GLuint64EXT, UInt64 GLint64, Int64 -GLuint64, Int64 +GLuint64, UInt64 diff --git a/Source/Bind/Specifications/enum.spec b/Source/Bind/Specifications/GL2/enum.spec similarity index 100% rename from Source/Bind/Specifications/enum.spec rename to Source/Bind/Specifications/GL2/enum.spec diff --git a/Source/Bind/Specifications/enumext.spec b/Source/Bind/Specifications/GL2/enumext.spec similarity index 100% rename from Source/Bind/Specifications/enumext.spec rename to Source/Bind/Specifications/GL2/enumext.spec diff --git a/Source/Bind/Specifications/gl.spec b/Source/Bind/Specifications/GL2/gl.spec similarity index 100% rename from Source/Bind/Specifications/gl.spec rename to Source/Bind/Specifications/GL2/gl.spec diff --git a/Source/Bind/Specifications/gl.tm b/Source/Bind/Specifications/GL2/gl.tm similarity index 100% rename from Source/Bind/Specifications/gl.tm rename to Source/Bind/Specifications/GL2/gl.tm diff --git a/Source/Bind/Specifications/enumglu.spec b/Source/Bind/Specifications/Glu/enumglu.spec similarity index 100% rename from Source/Bind/Specifications/enumglu.spec rename to Source/Bind/Specifications/Glu/enumglu.spec diff --git a/Source/Bind/Specifications/glu.spec b/Source/Bind/Specifications/Glu/glu.spec similarity index 100% rename from Source/Bind/Specifications/glu.spec rename to Source/Bind/Specifications/Glu/glu.spec diff --git a/Source/Bind/Specifications/glx.spec b/Source/Bind/Specifications/Glx/glx.spec similarity index 100% rename from Source/Bind/Specifications/glx.spec rename to Source/Bind/Specifications/Glx/glx.spec diff --git a/Source/Bind/Specifications/glx.tm b/Source/Bind/Specifications/Glx/glx.tm similarity index 100% rename from Source/Bind/Specifications/glx.tm rename to Source/Bind/Specifications/Glx/glx.tm diff --git a/Source/Bind/Specifications/glxenum.spec b/Source/Bind/Specifications/Glx/glxenum.spec similarity index 100% rename from Source/Bind/Specifications/glxenum.spec rename to Source/Bind/Specifications/Glx/glxenum.spec diff --git a/Source/Bind/Specifications/glxenumext.spec b/Source/Bind/Specifications/Glx/glxenumext.spec similarity index 100% rename from Source/Bind/Specifications/glxenumext.spec rename to Source/Bind/Specifications/Glx/glxenumext.spec diff --git a/Source/Bind/Specifications/glxext.spec b/Source/Bind/Specifications/Glx/glxext.spec similarity index 100% rename from Source/Bind/Specifications/glxext.spec rename to Source/Bind/Specifications/Glx/glxext.spec diff --git a/Source/Bind/Specifications/wgl.spec b/Source/Bind/Specifications/Wgl/wgl.spec similarity index 100% rename from Source/Bind/Specifications/wgl.spec rename to Source/Bind/Specifications/Wgl/wgl.spec diff --git a/Source/Bind/Specifications/wgl.tm b/Source/Bind/Specifications/Wgl/wgl.tm similarity index 100% rename from Source/Bind/Specifications/wgl.tm rename to Source/Bind/Specifications/Wgl/wgl.tm diff --git a/Source/Bind/Specifications/wglenum.spec b/Source/Bind/Specifications/Wgl/wglenum.spec similarity index 100% rename from Source/Bind/Specifications/wglenum.spec rename to Source/Bind/Specifications/Wgl/wglenum.spec diff --git a/Source/Bind/Specifications/wglenumext.spec b/Source/Bind/Specifications/Wgl/wglenumext.spec similarity index 100% rename from Source/Bind/Specifications/wglenumext.spec rename to Source/Bind/Specifications/Wgl/wglenumext.spec diff --git a/Source/Bind/Specifications/wglext.spec b/Source/Bind/Specifications/Wgl/wglext.spec similarity index 100% rename from Source/Bind/Specifications/wglext.spec rename to Source/Bind/Specifications/Wgl/wglext.spec diff --git a/Source/Bind/Structures/Constant.cs b/Source/Bind/Structures/Constant.cs index 9d4813d2..2c21c6fc 100644 --- a/Source/Bind/Structures/Constant.cs +++ b/Source/Bind/Structures/Constant.cs @@ -7,10 +7,8 @@ using System; using System.Collections.Generic; using System.Text; -namespace OpenTK.OpenGL.Bind +namespace Bind.Structures { - #region Constant class - /// /// Represents an opengl constant in C# format. Both the constant name and value /// can be retrieved or set. The value can be either a number, another constant @@ -18,7 +16,7 @@ namespace OpenTK.OpenGL.Bind /// public class Constant { - #region Name + #region public string Name string _name; @@ -37,7 +35,7 @@ namespace OpenTK.OpenGL.Bind #endregion - #region Value + #region public string Value string _value; @@ -56,6 +54,37 @@ namespace OpenTK.OpenGL.Bind #endregion + #region public string Reference + + string _reference; + + /// + /// Gets or sets the value of the opengl constant (eg. 0x00000001). + /// + public string Reference + { + get { return _reference; } + set + { + if (!String.IsNullOrEmpty(value)) + _reference = value.Trim(); + } + } + + #endregion + + #region public bool Unchecked + + private bool @unchecked = false; + + public bool Unchecked + { + get { return @unchecked; } + set { @unchecked = value; } + } + + #endregion + #region Constructors /// @@ -78,20 +107,24 @@ namespace OpenTK.OpenGL.Bind #endregion - #region public string ToString() + #region public override string ToString() /// /// Returns a string that represents the full constant declaration without decorations - /// (eg const uint GL_XXX_YYY = 0xDEADBEEF). + /// (eg GL_XXX_YYY = (int)0xDEADBEEF or GL_XXX_YYY = GL_ZZZ.FOOBAR). /// /// - override public string ToString() + public override string ToString() { - return Name + " = " + Value; + return String.Format( + "{0} = {1}((int){2}{3})", + Name, + Unchecked ? "unchecked" : "", + !String.IsNullOrEmpty(Reference) ? Reference + "." : "", + Value + ); } #endregion } - - #endregion } diff --git a/Source/Bind/Structures/Delegate.cs b/Source/Bind/Structures/Delegate.cs new file mode 100644 index 00000000..c85a5e64 --- /dev/null +++ b/Source/Bind/Structures/Delegate.cs @@ -0,0 +1,793 @@ +#region License +//Copyright (c) 2006 Stefanos Apostolopoulos +//See license.txt for license info +#endregion + +using System; +using System.Collections.Generic; +using System.Text; +using System.Runtime.InteropServices; +using System.Diagnostics; + +namespace Bind.Structures +{ + /// + /// Represents an opengl function. + /// The return value, function name, function parameters and opengl version can be retrieved or set. + /// + public class Delegate + { + #region --- Constructors --- + + public Delegate() + { + Parameters = new ParameterCollection(); + } + + public Delegate(Delegate d) + { + this.Category = new string(d.Category.ToCharArray()); + //this.Extension = !String.IsNullOrEmpty(d.Extension) ? new string(d.Extension.ToCharArray()) : ""; + this.Name = new string(d.Name.ToCharArray()); + this.NeedsWrapper = d.NeedsWrapper; + this.Parameters = new ParameterCollection(d.Parameters); + this.ReturnType = new Parameter(d.ReturnType); + this.Version = !String.IsNullOrEmpty(d.Version) ? new string(d.Version.ToCharArray()) : ""; + //this.Unsafe = d.Unsafe; + } + + #endregion + + #region --- Properties --- + + #region public bool CLSCompliant + + /// + /// Gets the CLSCompliant property. True if the delegate is not CLSCompliant. + /// + public bool CLSCompliant + { + get + { + if (Unsafe) + return false; + + if (!ReturnType.CLSCompliant) + return false; + + foreach (Parameter p in Parameters) + { + if (!p.CLSCompliant) + return false; + } + return true; + } + } + + #endregion + + #region public string Category + + private string _category; + + public string Category + { + get { return _category; } + set { _category = value; } + } + + #endregion + + #region public bool NeedsWrapper + + bool _needs_wrapper; + + /// + /// Indicates whether this function needs to be wrapped with a Marshaling function. + /// This flag is set if a function contains an Array parameter, or returns + /// an Array or string. + /// + public bool NeedsWrapper + { + get { return _needs_wrapper; } + set { _needs_wrapper = value; } + } + + #endregion + + #region public virtual bool Unsafe + + /// + /// True if the delegate must be declared as 'unsafe'. + /// + public virtual bool Unsafe + { + //get { return @unsafe; } + //set { @unsafe = value; } + get + { + if (ReturnType.Pointer) + return true; + + foreach (Parameter p in Parameters) + { + if (p.Pointer) + { + return true; + } + } + + return false; + } + } + + #endregion + + #region public Parameter ReturnType + + Parameter _return_type = new Parameter(); + /// + /// Gets or sets the return value of the opengl function. + /// + public Parameter ReturnType + { + get { return _return_type; } + set + { + _return_type = value; + } + } + + #endregion + + #region public string Name + + string _name; + /// + /// Gets or sets the name of the opengl function. + /// + public string Name + { + get { return _name; } + set + { + if (!String.IsNullOrEmpty(value)) + _name = value.Trim(); + } + } + + #endregion + + #region public ParameterCollection Parameters + + ParameterCollection _parameters; + + public ParameterCollection Parameters + { + get { return _parameters; } + set { _parameters = value; } + } + + #endregion + + #region public string Version + + string _version; + + /// + /// Defines the opengl version that introduced this function. + /// + public string Version + { + get { return _version; } + set { _version = value; } + } + + #endregion + + #region public bool Extension + + string _extension; + + public string Extension + { + //get { return _extension; } + //set { _extension = value; } + get + { + if (!String.IsNullOrEmpty(Name)) + { + _extension = Utilities.GetGL2Extension(Name); + return String.IsNullOrEmpty(_extension) ? "Core" : _extension; + } + else + { + return null; + } + } + } + + #endregion + + #endregion + + #region --- Strings --- + + #region public string CallString() + + public string CallString() + { + StringBuilder sb = new StringBuilder(); + + sb.Append(Settings.DelegatesClass); + sb.Append(".gl"); + sb.Append(Name); + sb.Append("("); + if (this.Name == "CallLists") + { + } + if (Parameters.Count > 0) + { + foreach (Parameter p in Parameters) + { + if (p.Unchecked) + sb.Append("unchecked((" + p.Type + ")"); + + if (p.Type != "object") + { + if (p.Type.ToLower().Contains("string")) + { + sb.Append(String.Format( + "({0}{1})", + p.Type, + (p.Array > 0) ? "[]" : "")); + + } + else + { + sb.Append(String.Format( + "({0}{1})", + p.Type, + (p.Pointer || p.Array > 0 || p.Reference) ? "*" : "")); + } + } + + sb.Append( + Utilities.Keywords.Contains(p.Name) ? "@" + p.Name : p.Name + ); + + if (p.Unchecked) + sb.Append(")"); + + sb.Append(", "); + } + sb.Replace(", ", ")", sb.Length - 2, 2); + } + else + { + sb.Append(")"); + } + + return sb.ToString(); + } + + #endregion + + #region public string DeclarationString() + + public string DeclarationString() + { + StringBuilder sb = new StringBuilder(); + + sb.Append(Unsafe ? "unsafe " : ""); + sb.Append(ReturnType); + sb.Append(" "); + sb.Append(Name); + sb.Append(Parameters.ToString()); + + return sb.ToString(); + } + + #endregion + + #region override public string ToString() + + /// + /// Gets the string representing the full function declaration without decorations + /// (ie "void glClearColor(float red, float green, float blue, float alpha)" + /// + override public string ToString() + { + StringBuilder sb = new StringBuilder(); + + sb.Append(Unsafe ? "unsafe " : ""); + sb.Append("delegate "); + sb.Append(ReturnType); + sb.Append(" "); + sb.Append(Name); + sb.Append(Parameters.ToString()); + + return sb.ToString(); + } + + #endregion + + public Delegate GetCLSCompliantDelegate(Dictionary CSTypes) + { + Delegate f = new Delegate(this); + + for (int i = 0; i < f.Parameters.Count; i++) + { + f.Parameters[i].Type = f.Parameters[i].GetCLSCompliantType(CSTypes); + } + + f.ReturnType.Type = f.ReturnType.GetCLSCompliantType(CSTypes); + + return f; + } + + #endregion + + #region --- Wrapper Creation --- + + #region public List CreateWrappers(Dictionary CSTypes) + + public List CreateWrappers(Dictionary CSTypes) + { + if (this.Name == "MapBuffer") + { + } + + List wrappers = new List(); + if (!NeedsWrapper) + { + // No special wrapper needed - just call this delegate: + Function f = new Function(this); + + if (f.ReturnType.Type.ToLower().Contains("void")) + f.Body.Add(String.Format("{0};", f.CallString())); + else + f.Body.Add(String.Format("return {0};", f.CallString())); + + wrappers.Add(f); + } + else + { + // We have to add wrappers for all possible WrapperTypes. + Function f; + + // First, check if the return type needs wrapping: + switch (this.ReturnType.WrapperType) + { + // If the function returns a string (glGetString) we must manually marshal it + // using Marshal.PtrToStringXXX. Otherwise, the GC will try to free the memory + // used by the string, resulting in corruption (the memory belongs to the + // unmanaged boundary). + case WrapperTypes.StringReturnType: + f = new Function(this); + f.ReturnType.Type = "System.String"; + + f.Body.Add( + String.Format( + "return System.Runtime.InteropServices.Marshal.PtrToStringAnsi({0});", + this.CallString() + ) + ); + + wrappers.Add(f); + return wrappers; // Only occurs in glGetString, there's no need to check parameters. + + // If the function returns a void* (GenericReturnValue), we'll have to return an IntPtr. + // The user will unfortunately need to marshal this IntPtr to a data type manually. + case WrapperTypes.GenericReturnType: + ReturnType.Type = "IntPtr"; + ReturnType.Pointer = false; + /* + f = new Function(this); + f.ReturnType.Type = "IntPtr"; + f.ReturnType.Pointer = false; + + if (f.ReturnType.Type.ToLower().Contains("void")) + f.Body.Add(String.Format("{0};", f.CallString())); + else + f.Body.Add(String.Format("return {0};", f.CallString())); + + wrappers.Add(f); + */ + break; + + case WrapperTypes.None: + default: + // No return wrapper needed + break; + } + + // Then, create wrappers for each parameter: + WrapParameters(new Function(this), wrappers, CSTypes); + } + + return wrappers; + } + + #endregion + + #region protected void WrapParameters(Function function, List wrappers) + + protected static int index = 0; + + /// + /// This function needs some heavy refactoring. I'm ashamed I ever wrote it, but it works... + /// What it does is this: it adds to the wrapper list all possible wrapper permutations + /// for functions that have more than one IntPtr parameter. Example: + /// "void Delegates.f(IntPtr p, IntPtr q)" where p and q are pointers to void arrays needs the following wrappers: + /// "void f(IntPtr p, IntPtr q)" + /// "void f(IntPtr p, object q)" + /// "void f(object p, IntPtr q)" + /// "void f(object p, object q)" + /// + protected void WrapParameters(Function function, List wrappers, Dictionary CSTypes) + { + if (function.Name == "LineStipple") + { + } + + if (index == 0) + { + bool containsPointerParameters = false; + // Check if there are any IntPtr parameters (we may have come here from a ReturnType wrapper + // such as glGetString, which contains no IntPtr parameters) + foreach (Parameter p in function.Parameters) + { + if (p.Pointer) + { + containsPointerParameters = true; + break; + } + } + + if (containsPointerParameters) + { + wrappers.Add(DefaultWrapper(function)); + } + else + { + wrappers.Add(DefaultWrapper(function)); + return; + } + } + + if (index >= 0 && index < function.Parameters.Count) + { + Function f; + + if (function.Parameters[index].WrapperType == WrapperTypes.None) + { + // No wrapper needed, visit the next parameter + ++index; + WrapParameters(function, wrappers, CSTypes); + --index; + } + else + { + switch (function.Parameters[index].WrapperType) + { + case WrapperTypes.ArrayParameter: + // Recurse to the last parameter + ++index; + WrapParameters(function, wrappers, CSTypes); + --index; + + // On stack rewind, create array wrappers + f = ArrayWrapper(new Function(function), index, CSTypes); + wrappers.Add(f); + + // Recurse to the last parameter again, keeping the Array wrappers + ++index; + WrapParameters(f, wrappers, CSTypes); + --index; + + // On stack rewind, create Ref wrappers. + f = ReferenceWrapper(new Function(function), index, CSTypes); + wrappers.Add(f); + + // Keeping the current Ref wrapper, visit all other parameters once more + ++index; + WrapParameters(f, wrappers, CSTypes); + --index; + + break; + + case WrapperTypes.GenericParameter: + // Recurse to the last parameter + ++index; + WrapParameters(function, wrappers, CSTypes); + --index; + + // On stack rewind, create array wrappers + f = GenericWrapper(new Function(function), index, CSTypes); + wrappers.Add(f); + + // Keeping the current Object wrapper, visit all other parameters once more + ++index; + WrapParameters(f, wrappers, CSTypes); + --index; + + break; + } + } + } + } + + #endregion + + #region protected Function GenericWrapper(Function function, int index, Dictionary CSTypes) + + protected Function GenericWrapper(Function function, int index, Dictionary CSTypes) + { + // Search and replace IntPtr parameters with the known parameter types: + function.Parameters[index].Reference = false; + function.Parameters[index].Array = 0; + function.Parameters[index].Pointer = false; + function.Parameters[index].Type = "object"; + function.Parameters[index].Flow = Parameter.FlowDirection.Undefined; + + // In the function body we should pin all objects in memory before calling the + // low-level function. + function.Body.Clear(); + //function.Body.AddRange(GetBodyWithFixedPins(function)); + function.Body.AddRange(GetBodyWithPins(function, CSTypes, false)); + + return function; + } + + #endregion + + #region protected Function ReferenceWrapper(Function function, int index, Dictionary CSTypes) + + protected Function ReferenceWrapper(Function function, int index, Dictionary CSTypes) + { + // Search and replace IntPtr parameters with the known parameter types: + function.Parameters[index].Reference = true; + function.Parameters[index].Array = 0; + function.Parameters[index].Pointer = false; + + // In the function body we should pin all objects in memory before calling the + // low-level function. + function.Body.Clear(); + function.Body.AddRange(GetBodyWithPins(function, CSTypes, false)); + + return function; + } + + #endregion + + #region protected Function ArrayWrapper(Function function, int index, Dictionary CSTypes) + + protected Function ArrayWrapper(Function function, int index, Dictionary CSTypes) + { + // Search and replace IntPtr parameters with the known parameter types: + function.Parameters[index].Array = 1; + function.Parameters[index].Pointer = false; + function.Parameters[index].Flow = Parameter.FlowDirection.Undefined; + + // In the function body we should pin all objects in memory before calling the + // low-level function. + function.Body.Clear(); + function.Body.AddRange(GetBodyWithPins(function, CSTypes, false)); + + return function; + } + + #endregion + + #region protected Function DefaultWrapper(Function f) + + protected Function DefaultWrapper(Function f) + { + bool returns = f.ReturnType.Type.ToLower().Contains("void") && !f.ReturnType.Pointer; + string callString = String.Format( + "{0} {1}{2}; {3}", + Unsafe ? "unsafe {" : "", + returns ? "" : "return ", + f.CallString(), + Unsafe ? "}" : ""); + + f.Body.Add(callString); + + return f; + } + + #endregion + + #region protected static FunctionBody GetBodyWithPins(Function function, Dictionary CSTypes, bool wantCLSCompliance) + + /// + /// Generates a body which calls the specified function, pinning all needed parameters. + /// + /// + protected static FunctionBody GetBodyWithPins(Function function, Dictionary CSTypes, bool wantCLSCompliance) + { + // We'll make changes, but we want the original intact. + Function f = new Function(function); + f.Body.Clear(); + // Unsafe only if + //function.Unsafe = false; + + // Add default initliazers for out parameters: + foreach (Parameter p in function.Parameters) + { + if (p.Flow == Parameter.FlowDirection.Out) + { + f.Body.Add( + String.Format( + "{0} = default({1});", + p.Name, + p.GetFullType(CSTypes, wantCLSCompliance) + ) + ); + } + } + // All GCHandles statements will go here. This will allow to place only one opening '{' + // on fixed statements. + int handleStart = f.Body.Count; + + // Indicates the index where the last GCHandle statement is. Used to add an unsafe stamement + // (if needed) at exactl that spot, i.e. after the GCHandles but before the fixed statements. + int handleEnd = f.Body.Count; + + // True if at least on GCHandle is allocated. Used to remove the try { } finally { } + // block if no handle has been allocated. + bool handleAllocated = false; + + // True if function body contains at least one fixed statement. Add a statement-level + // unsafe block if true (and the function is not unsafe at the function-level). + bool fixedAllocated = false; + + // Obtain pointers by pinning the parameters + foreach (Parameter p in f.Parameters) + { + if (p.NeedsPin) + { + // Use GCHandle to obtain pointer to generic parameters and 'fixed' for arrays. + // This is because fixed can only take the address of fields, not managed objects. + if (p.WrapperType == WrapperTypes.GenericParameter) + { + f.Body.Insert( + handleStart, + String.Format( + "{0} {1} = {0}.Alloc({2}, System.Runtime.InteropServices.GCHandleType.Pinned);", + "System.Runtime.InteropServices.GCHandle", + p.Name + "_ptr", + p.Name + ) + ); + // Note! The following line modifies f.Parameters, *not* function.Parameters + p.Name = "(void*)" + p.Name + "_ptr.AddrOfPinnedObject()"; + + handleAllocated = true; + + handleEnd++; + } + else + { + f.Body.Add( + String.Format( + " fixed ({0}* {1} = {2})", + wantCLSCompliance && !p.CLSCompliant ? p.GetCLSCompliantType(CSTypes) : p.Type, + p.Name + "_ptr", + p.Array > 0 ? p.Name : "&" + p.Name + ) + ); + p.Name = p.Name + "_ptr"; + + fixedAllocated = true; + } + } + } + + if (!function.Unsafe) + { + f.Body.Insert(handleEnd, "unsafe"); + f.Body.Insert(handleEnd + 1, "{"); + } + + if (handleAllocated) + { + f.Body.Add(" try"); + } + + f.Body.Add(" {"); + // Add delegate call: + if (f.ReturnType.Type.ToLower().Contains("void")) + f.Body.Add(String.Format(" {0};", f.CallString())); + else + f.Body.Add(String.Format(" {0} {1} = {2};", f.ReturnType.Type, "retval", f.CallString())); + + // Assign out parameters: + foreach (Parameter p in function.Parameters) + { + if (p.Flow == Parameter.FlowDirection.Out) + { + // Check each out parameter. If it has been pinned, get the Target of the GCHandle. + // Otherwise, nothing needs be done. + if (p.NeedsPin) + { + if (p.WrapperType == WrapperTypes.GenericParameter) + { + f.Body.Add( + String.Format( + " {0} = ({1}){2}.Target;", + p.Name, + p.Type, + p.Name + "_ptr" + ) + ); + } + else + { + f.Body.Add( + String.Format( + " {0} = *{0}_ptr;", + p.Name + ) + ); + } + } + } + } + + // Return: + if (!f.ReturnType.Type.ToLower().Contains("void")) + { + f.Body.Add(" return retval;"); + } + + if (handleAllocated) + { + f.Body.Add(" }"); + f.Body.Add(" finally"); + f.Body.Add(" {"); + foreach (Parameter p in function.Parameters) + { + // Free all allocated GCHandles + if (p.NeedsPin) + { + if (p.WrapperType == WrapperTypes.GenericParameter) + f.Body.Add(String.Format(" {0}_ptr.Free();", p.Name)); + //else + // f.Body.Add("}"); + } + } + } + f.Body.Add(" }"); + + if (!function.Unsafe) + { + f.Body.Add("}"); + } + + return f.Body; + } + + #endregion + + #endregion + } + + class DelegateCollection : Dictionary + { + public void Add(Delegate d) + { + if (!this.ContainsKey(d.Name)) + { + this.Add(d.Name, d); + } + else + { + Trace.WriteLine(String.Format( + "Spec error: function {0} redefined, ignoring second definition.", + d.Name)); + } + } + } +} diff --git a/Source/Bind/Structures/Enum.cs b/Source/Bind/Structures/Enum.cs index be48a3f6..e71a93c1 100644 --- a/Source/Bind/Structures/Enum.cs +++ b/Source/Bind/Structures/Enum.cs @@ -7,12 +7,20 @@ using System; using System.Collections.Generic; using System.Text; -namespace OpenTK.OpenGL.Bind +namespace Bind.Structures { #region class Enum public class Enum { + public Enum() + { } + + public Enum(string name) + { + Name = name; + } + string _name; public string Name @@ -33,17 +41,40 @@ namespace OpenTK.OpenGL.Bind { StringBuilder sb = new StringBuilder(); - sb.AppendLine(" public enum " + Name + " : uint"); - sb.AppendLine(" {"); + sb.AppendLine("public enum " + Name); + sb.AppendLine("{"); foreach (Constant c in ConstantCollection.Values) { - sb.AppendLine(" " + c.Name + " = " + c.Value + ","); + sb.Append(" "); + sb.Append(c.ToString()); + sb.AppendLine(","); } - sb.AppendLine(" }"); + sb.AppendLine("}"); return sb.ToString(); } } #endregion + + #region class EnumCollection + + class EnumCollection : Dictionary + { + /* + public override string ToString() + { + StringBuilder sb = new StringBuilder(); + + foreach (Bind.Structures.Enum e in this.Values) + { + sb.AppendLine(e.ToString()); + } + + return sb.ToString(); + } + */ + } + + #endregion } diff --git a/Source/Bind/Structures/Function.cs b/Source/Bind/Structures/Function.cs index 74fe247c..0b3f183c 100644 --- a/Source/Bind/Structures/Function.cs +++ b/Source/Bind/Structures/Function.cs @@ -1,45 +1,44 @@ -#region License -//Copyright (c) 2006 Stefanos Apostolopoulos -//See license.txt for license info -#endregion - -using System; +using System; using System.Collections.Generic; using System.Text; -namespace OpenTK.OpenGL.Bind +namespace Bind.Structures { - #region class Function - - /// - /// Represents an opengl function. - /// The return value, function name, function parameters and opengl version can be retrieved or set. - /// - public class Function + public class Function : Delegate { - #region Constructors + #region --- Constructors --- public Function() + : base() { - Parameters = new ParameterCollection(); Body = new FunctionBody(); } public Function(Function f) + : base(f) { this.Body = new FunctionBody(f.Body); - this.Category = new string(f.Category.ToCharArray()); - this.Extension = f.Extension; - this.Name = new string(f.Name.ToCharArray()); - this.NeedsWrapper = f.NeedsWrapper; - this.Parameters = new ParameterCollection(f.Parameters); - this.ReturnValue = new string(f.ReturnValue.ToCharArray()); - this.Version = new string(f.Version.ToCharArray()); - this.WrapperType = f.WrapperType; + } + + public Function(Delegate d) + : base(d) + { + this.Body = new FunctionBody(); } #endregion + public override bool Unsafe + { + get + { + if (Settings.Compatibility == Settings.Legacy.Tao) + return false; + + return base.Unsafe; + } + } + #region Function body FunctionBody _body; @@ -49,169 +48,28 @@ namespace OpenTK.OpenGL.Bind get { return _body; } set { _body = value; } } - - #endregion - - #region Category property - - private string _category; - - public string Category - { - get { return _category; } - set { _category = value; } - } #endregion - #region Wrapper type property + #region public override string ToString() - private WrapperTypes _wrapper_type = WrapperTypes.None; - - public WrapperTypes WrapperType - { - get { return _wrapper_type; } - set { _wrapper_type = value; } - } - - #endregion - - #region Needs wrapper property - - bool _needs_wrapper; - - /// - /// Indicates whether this function needs to be wrapped with a Marshaling function. - /// This flag is set if a function contains an Array parameter, or returns - /// an Array or string. - /// - public bool NeedsWrapper - { - get { return _needs_wrapper; } - set { _needs_wrapper = value; } - } - - #endregion - - #region Return value property - - string _return_value; - /// - /// Gets or sets the return value of the opengl function. - /// - public string ReturnValue - { - get { return _return_value; } - set { _return_value = value; } - } - - #endregion - - #region Name property - - string _name; - /// - /// Gets or sets the name of the opengl function. - /// - public string Name - { - get { return _name; } - set - { - if (!String.IsNullOrEmpty(value)) - _name = value.Trim(); - else - _name = value; - } - } - - #endregion - - #region Parameter collection property - - ParameterCollection _parameters; - - public ParameterCollection Parameters - { - get { return _parameters; } - set { _parameters = value; } - } - - #endregion - - #region Version property - - string _version; - - /// - /// Defines the opengl version that introduced this function. - /// - public string Version - { - get { return _version; } - set { _version = value; } - } - - #endregion - - #region Extension property - - bool _extension = false; - - public bool Extension - { - get { return _extension; } - set { _extension = value; } - } - - #endregion - - #region Call function string - - public string CallString() + public override string ToString() { StringBuilder sb = new StringBuilder(); + + sb.Append(Unsafe ? "unsafe " : ""); + sb.Append(ReturnType); + sb.Append(" "); + if (Settings.Compatibility == Settings.Legacy.Tao) + { + sb.Append("gl"); + } sb.Append(Name); - sb.Append("("); - foreach (Parameter p in Parameters) - { - if (p.Unchecked) - sb.Append("unchecked((" + p.Type + ")"); - - sb.Append(p.Name); - - if (p.Unchecked) - sb.Append(")"); - - sb.Append(", "); - } - sb.Replace(", ", ")", sb.Length - 2, 2); - - return sb.ToString(); - } - - #endregion - - #region ToString function - - /// - /// Gets the string representing the full function declaration without decorations - /// (ie "void glClearColor(float red, float green, float blue, float alpha)" - /// - override public string ToString() - { - return ToString(""); - } - - public string ToString(string indentation) - { - StringBuilder sb = new StringBuilder(); - - sb.Append(indentation + ReturnValue + " " + Name + Parameters.ToString()); + sb.Append(Parameters.ToString(true)); if (Body.Count > 0) { sb.AppendLine(); - sb.Append(Body.ToString(indentation)); + sb.Append(Body.ToString()); } return sb.ToString(); @@ -219,9 +77,36 @@ namespace OpenTK.OpenGL.Bind #endregion - } + #region public Function GetCLSCompliantFunction(Dictionary CSTypes) - #endregion + public Function GetCLSCompliantFunction(Dictionary CSTypes) + { + Function f = new Function(this); + + for (int i = 0; i < f.Parameters.Count; i++) + { + f.Parameters[i].Type = f.Parameters[i].GetCLSCompliantType(CSTypes); + } + + f.Body.Clear(); + if (!f.NeedsWrapper) + { + f.Body.Add((f.ReturnType.Type != "void" ? "return " + this.CallString() : this.CallString()) + ";"); + } + else + { + f.Body.AddRange(Function.GetBodyWithPins(this, CSTypes, true)); + } + + // The type system cannot differentiate between functions with the same parameters + // but different return types. Tough, only CLS-Compliant function in that case. + //f.ReturnType.Type = f.ReturnType.GetCLSCompliantType(CSTypes); + + return f; + } + + #endregion + } #region class FunctionBody : List @@ -240,27 +125,46 @@ namespace OpenTK.OpenGL.Bind } public override string ToString() - { - return ToString(""); - } - - public string ToString(string indentation) { if (this.Count == 0) return String.Empty; StringBuilder sb = new StringBuilder(this.Count); - - sb.AppendLine(indentation + "{"); + + sb.AppendLine("{"); foreach (string s in this) { - sb.AppendLine(indentation + " " + s); + sb.AppendLine(" " + s); } - sb.AppendLine(indentation + "}"); + sb.AppendLine("}"); return sb.ToString(); } } #endregion + + class FunctionCollection : Dictionary> + { + public void Add(Function f) + { + if (!this.ContainsKey(f.Extension)) + { + this.Add(f.Extension, new List()); + this[f.Extension].Add(f); + } + else + { + this[f.Extension].Add(f); + } + } + + public void AddRange(IEnumerable functions) + { + foreach (Function f in functions) + { + this.Add(f); + } + } + } } diff --git a/Source/Bind/Structures/Parameter.cs b/Source/Bind/Structures/Parameter.cs index 2a1c471e..b123d611 100644 --- a/Source/Bind/Structures/Parameter.cs +++ b/Source/Bind/Structures/Parameter.cs @@ -8,7 +8,7 @@ using System.Collections.Generic; using System.Text; using System.Runtime.InteropServices; -namespace OpenTK.OpenGL.Bind +namespace Bind.Structures { #region Parameter class @@ -35,15 +35,19 @@ namespace OpenTK.OpenGL.Bind if (p == null) return; - this.Array = p.Array; - this.Flow = p.Flow; - this.Name = new string(p.Name.ToCharArray()); - this.NeedsWrapper = p.NeedsWrapper; - this.PreviousType = new string(p.PreviousType.ToCharArray()); - this.Type = new string(p.Type.ToCharArray()); + this.Name = !String.IsNullOrEmpty(p.Name) ? new string(p.Name.ToCharArray()) : ""; + //this.NeedsWrapper = p.NeedsWrapper; + this.PreviousType = !String.IsNullOrEmpty(p.PreviousType) ? new string(p.PreviousType.ToCharArray()) : ""; this.Unchecked = p.Unchecked; this.UnmanagedType = p.UnmanagedType; this.WrapperType = p.WrapperType; + + this.Type = new string(p.Type.ToCharArray()); + this.Flow = p.Flow; + this.Array = p.Array; + this.Pointer = p.Pointer; + this.Reference = p.Reference; + } #endregion @@ -84,12 +88,34 @@ namespace OpenTK.OpenGL.Bind /// public string Type { - get { return _type; } + //get { return _type; } + get + { + //if (Pointer && Settings.Compatibility == Settings.Legacy.Tao) + // return "IntPtr"; + + return _type; + } set { - if (_type != null) + if (!String.IsNullOrEmpty(_type)) PreviousType = _type; - _type = value; + if (!String.IsNullOrEmpty(value)) + _type = value.Trim(); + if (_type.EndsWith("*")) + { + _type = _type.TrimEnd('*'); + Pointer = true; + } + + clsCompliant = + !( + (Pointer && (Settings.Compatibility != Settings.Legacy.Tao)) || + (Type.Contains("GLu") && !Type.Contains("GLubyte")) || + Type == "GLbitfield" || + Type.Contains("GLhandle") || + Type.Contains("GLhalf") || + Type == "GLbyte"); } } @@ -134,19 +160,54 @@ namespace OpenTK.OpenGL.Bind #endregion - #region Array property + #region public bool Reference - bool _array = false; + bool reference; - public bool Array + public bool Reference { - get { return _array; } - set { _array = value; } + get { return reference; } + set { reference = value; } } #endregion - #region Unchecked property + #region public bool Array + + int array; + + public int Array + { + get { return array; } + set { array = value > 0 ? value : 0; } + } + + #endregion + + #region public bool Pointer + + bool pointer = false; + + public bool Pointer + { + get { return pointer; } + set { pointer = value; } + } + + #endregion + + #region public bool NeedsPin + + public bool NeedsPin + { + get { return + (Array > 0 || Reference || Type == "object") && + !Type.ToLower().Contains("string"); } + } + + #endregion + + #region public bool Unchecked private bool _unchecked; @@ -158,18 +219,6 @@ namespace OpenTK.OpenGL.Bind #endregion - #region NeedsWrapper property - - private bool _needs_wrapper; - - public bool NeedsWrapper - { - get { return _needs_wrapper; } - set { _needs_wrapper = value; } - } - - #endregion - #region WrapperType property private WrapperTypes _wrapper_type = WrapperTypes.None; @@ -182,29 +231,137 @@ namespace OpenTK.OpenGL.Bind #endregion - #region ToString function + #region public bool CLSCompliant + + private bool clsCompliant; + + public bool CLSCompliant + { + get + { + // Checked when setting the Type property. + return clsCompliant || (Pointer && Settings.Compatibility == Settings.Legacy.Tao); + } + } + + #endregion + + #region public string GetFullType() + + public string GetFullType(Dictionary CSTypes, bool compliant) + { + if (Pointer && Settings.Compatibility == Settings.Legacy.Tao) + return "IntPtr"; + + if (!compliant) + { + return + Type + + (Pointer ? "*" : "") + + (Array > 0 ? "[]" : ""); + } + + return + GetCLSCompliantType(CSTypes) + + (Pointer ? "*" : "") + + (Array > 0 ? "[]" : ""); + + } + + #endregion + + #region public string GetCLSCompliantType(Dictionary CSTypes) + + public string GetCLSCompliantType(Dictionary CSTypes) + { + if (!CLSCompliant) + { + if (Pointer && Settings.Compatibility == Settings.Legacy.Tao) + return "IntPtr"; + + if (CSTypes.ContainsKey(Type)) + { + switch (CSTypes[Type]) + { + case "UInt16": + return "Int16"; + case "UInt32": + return "Int32"; + case "UInt64": + return "Int64"; + case "SByte": + return "Byte"; + } + } + } + + return Type; + } + + #endregion + + #region override public string ToString() + override public string ToString() + { + return ToString(false); + } + + #endregion + + #region public string ToString(bool taoCompatible) + + public string ToString(bool taoCompatible) { StringBuilder sb = new StringBuilder(); - if (UnmanagedType == UnmanagedType.AsAny && Flow == FlowDirection.In) - sb.Append("[MarshalAs(UnmanagedType.AsAny)] "); + //if (UnmanagedType == UnmanagedType.AsAny && Flow == FlowDirection.In) + // sb.Append("[MarshalAs(UnmanagedType.AsAny)] "); - if (UnmanagedType == UnmanagedType.LPArray) - sb.Append("[MarshalAs(UnmanagedType.LPArray)] "); + //if (UnmanagedType == UnmanagedType.LPArray) + // sb.Append("[MarshalAs(UnmanagedType.LPArray)] "); //if (Flow == FlowDirection.Out && !Array && !(Type == "IntPtr")) // sb.Append("out "); - sb.Append(Type); - if (Array) - sb.Append("[]"); + if (Reference) + { + if (Flow == FlowDirection.Out) + sb.Append("out "); + else + sb.Append("ref "); + } - sb.Append(" "); - sb.Append(Name); + if (taoCompatible && Settings.Compatibility == Settings.Legacy.Tao) + { + if (Pointer) + { + sb.Append("IntPtr"); + } + else + { + sb.Append(Type); + if (Array > 0) + sb.Append("[]"); + } + } + else + { + sb.Append(Type); + if (Pointer) + sb.Append("*"); + if (Array > 0) + sb.Append("[]"); + } + if (!String.IsNullOrEmpty(Name)) + { + sb.Append(" "); + sb.Append(Utilities.Keywords.Contains(Name) ? "@" + Name : Name); + } return sb.ToString(); } + #endregion } @@ -236,10 +393,30 @@ namespace OpenTK.OpenGL.Bind #region override public string ToString() /// - /// + /// Gets the parameter declaration string. /// /// The parameter list of an opengl function in the form ( [parameters] ) override public string ToString() + { + return ToString(false, null); + } + + #endregion + + public string ToString(bool taoCompatible) + { + return ToString(true, null); + } + + #region public string ToString(bool taoCompatible, Dictionary CSTypes) + + /// + /// Gets the parameter declaration string. + /// + /// If true, all types will be replaced by their CLSCompliant C# equivalents + /// The list of C# types equivalent to the OpenGL types. + /// The parameter list of an opengl function in the form ( [parameters] ) + public string ToString(bool taoCompatible, Dictionary CSTypes) { StringBuilder sb = new StringBuilder(); sb.Append("("); @@ -247,7 +424,14 @@ namespace OpenTK.OpenGL.Bind { foreach (Parameter p in this) { - sb.Append(p.ToString()); + if (taoCompatible) + { + sb.Append(p.ToString(true)); + } + else + { + sb.Append(p.ToString()); + } sb.Append(", "); } sb.Replace(", ", ")", sb.Length - 2, 2); @@ -258,6 +442,8 @@ namespace OpenTK.OpenGL.Bind return sb.ToString(); } + #endregion + public bool ContainsType(string type) { foreach (Parameter p in this) @@ -265,87 +451,6 @@ namespace OpenTK.OpenGL.Bind return true; return false; } - - #endregion - - #region public ParameterCollection ReplaceAll(Parameter, Parameter) - - /// - /// Replaces all parameters that match the old_param with the new_param. - /// - /// - /// - /// - /// The PreviousType property is ignored in parameter matching, and is set to the previous type in case of replacement. - public ParameterCollection ReplaceAll(Parameter old_param, Parameter new_param) - { - if (old_param == null || new_param == null) - return null; - - ParameterCollection pc = new ParameterCollection(this); - - foreach (Parameter p in pc) - { - if (p.Array == old_param.Array && - p.Flow == old_param.Flow && - p.Name == old_param.Name && - //p.PreviousType == old_param.PreviousType && - p.Type == old_param.Type && - p.UnmanagedType == old_param.UnmanagedType) - { - p.Array = new_param.Array; - p.Flow = new_param.Flow; - p.Name = new_param.Name; - p.PreviousType = p.Type; - p.Type = new_param.Type; - p.UnmanagedType = new_param.UnmanagedType; - } - } - - return pc; - } - - #endregion - - #region public ParameterCollection Replace(Parameter, Parameter) - - /// - /// Replaces the first parameter that matches old_param with new_param. - /// - /// - /// - /// - /// The PreviousType property is ignored in parameter matching, and is set to the previous type in case of replacement. - public ParameterCollection Replace(Parameter old_param, Parameter new_param) - { - if (old_param == null || new_param == null) - return null; - - ParameterCollection pc = new ParameterCollection(this); - - foreach (Parameter p in pc) - { - if (p.Array == old_param.Array && - p.Flow == old_param.Flow && - p.Name == old_param.Name && - //p.PreviousType == old_param.PreviousType && - p.Type == old_param.Type && - p.UnmanagedType == old_param.UnmanagedType) - { - p.Array = new_param.Array; - p.Flow = new_param.Flow; - p.Name = new_param.Name; - p.PreviousType = p.Type; - p.Type = new_param.Type; - p.UnmanagedType = new_param.UnmanagedType; - return pc; - } - } - - return pc; - } - - #endregion } #endregion diff --git a/Source/Bind/Utilities.cs b/Source/Bind/Utilities.cs new file mode 100644 index 00000000..8339a1ef --- /dev/null +++ b/Source/Bind/Utilities.cs @@ -0,0 +1,231 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.IO; +using Bind.Structures; + +namespace Bind +{ + #region WrapperTypes enum + + [Flags] + public enum WrapperTypes + { + /// + /// No wrapper needed. + /// + None = 0, + /// + /// Function takes bool parameter - C uses Int for bools, so we have to marshal. + /// + BoolParameter, + /// + /// Function takes generic parameters - add ref/out generic and generic overloads. + /// + GenericParameter, + /// + /// Function takes arrays as parameters - add ref/out and ([Out]) array overloads. + /// + ArrayParameter, + /// + /// Function with bitmask parameters. Bitmask parameters map to UInt, but since we can only use signed + /// types (for CLS compliance), we must add the unchecked keyword. + /// Usually found in bitmasks + /// + UncheckedParameter, + /// + /// Function that takes (in/ref/out) a naked pointer as a parameter - we pass an IntPtr. + /// + PointerParameter, + /// + /// Function returns string - needs manual marshalling through IntPtr to prevent the managed GC + /// from freeing memory allocated on the unmanaged side (e.g. glGetString). + /// + StringReturnType, + /// + /// Function returns a void pointer - maps to IntPtr, and the user has to manually marshal the type. + /// + GenericReturnType, + /// + /// Function returns a typed pointer - we have to copy the data to an array to protect it from the GC. + /// + ArrayReturnType + } + + #endregion + + public static class Utilities + { + public static char[] Separators = { ' ', '\n', ',', '(', ')', ';', '#' }; + + #region internal StreamReader OpenSpecFile(string file) + + internal static StreamReader OpenSpecFile(string folder, string file) + { + string path = Path.Combine(folder, file); + return new StreamReader(path); + } + + #endregion + + #region C# keywords + + public static readonly List Keywords = new List( + new string[] + { + "abstract", "event", "new", "struct", + "as", "explicit", "null", "switch", + "base", "extern", "object", "this", + "bool", "false", "operator", "throw", + "break", "finally", "out", "true", + "byte", "fixed", "override", "try", + "case", "float", "params", "typeof", + "catch", "for", "private", "uint", + "char", "foreach", "protected", "ulong", + "checked", "goto", "public", "unchecked", + "class", "if", "readonly", "unsafe", + "const", "implicit", "ref", "ushort", + "continue", "in", "return", "using", + "decimal", "int", "sbyte", "virtual", + "default", "interface", "sealed", "volatile", + "delegate", "internal", "short", "void", + "do", "is", "sizeof", "while", + "double", "lock", "stackalloc", + "else", "long", "static", + "enum", "namespace", "string" + } + ); + + #endregion + + #region internal static void Merge(EnumCollection enums, Bind.Structures.Enum t) + + /// + /// Merges the given enum into the enum list. If an enum of the same name exists, + /// it merges their respective constants. + /// + /// + /// + internal static void Merge(EnumCollection enums, Bind.Structures.Enum t) + { + if (!enums.ContainsKey(t.Name)) + { + enums.Add(t.Name, t); + } + else + { + Bind.Structures.Enum e = enums[t.Name]; + foreach (Bind.Structures.Constant c in t.ConstantCollection.Values) + { + Merge(e, c); + } + } + } + + #endregion + + #region internal static Bind.Structures.Enum Merge(Bind.Structures.Enum s, Bind.Structures.Constant t) + + /// + /// Places a new constant in the specified enum, if it doesn't already exist. + /// The existing constant is replaced iff the new has a numeric value and the old + /// has a reference value (eg 0x5 is preferred over AttribMask.Foo) + /// + /// + /// + /// + internal static Bind.Structures.Enum Merge(Bind.Structures.Enum s, Bind.Structures.Constant t) + { + if (!s.ConstantCollection.ContainsKey(t.Name)) + { + s.ConstantCollection.Add(t.Name, t); + } + else + { + // Tried to add a constant that already exists. If one constant + // is like: 'Foo = 0x5' and the other like: 'Foo = Bar.Foo', then + // keep the first one. + if (!Char.IsDigit(((Constant)s.ConstantCollection[t.Name]).Value[0])) + { + s.ConstantCollection.Remove(t.Name); + s.ConstantCollection.Add(t.Name, t); + } + } + + return s; + } + + #endregion + + #region internal static string StripGL2Extension(Function f) + + internal static string StripGL2Extension(Function f) + { + string ext = GetGL2Extension(f.Name); + if (String.IsNullOrEmpty(ext)) + return null; + + f.Name = f.Name.Substring(0, f.Name.Length - ext.Length); + return ext; + } + + #endregion + + #region internal static string GetGL2Extension(string name) + + internal static string GetGL2Extension(string name) + { + if (name.EndsWith("ARB")) { return "ARB"; } + if (name.EndsWith("EXT")) { return "EXT"; } + if (name.EndsWith("ATI")) { return "ATI"; } + if (name.EndsWith("ATIX")) { return "ATIX"; } + if (name.EndsWith("NV")) { return "NV"; } + if (name.EndsWith("SUN")) { return "SUN"; } + if (name.EndsWith("SUNX")) { return "SUNX"; } + if (name.EndsWith("SGI")) { return "SGI"; } + if (name.EndsWith("SGIS")) { return "SGIS"; } + if (name.EndsWith("SGIX")) { return "SGIX"; } + if (name.EndsWith("MESA")) { return "MESA"; } + if (name.EndsWith("G3DFX")) { return "G3DFX"; } + if (name.EndsWith("IBM")) { return "IBM"; } + if (name.EndsWith("GREMEDY")) { return "GREMEDY"; } + if (name.EndsWith("HP")) { return "HP"; } + if (name.EndsWith("PGI")) { return "PGI"; } + if (name.EndsWith("INGR")) { return "INGR"; } + if (name.EndsWith("APPLE")) { return "APPLE"; } + if (name.EndsWith("OML")) { return "OML"; } + if (name.EndsWith("I3D")) { return "I3D"; } + return null; + } + + #endregion + + #region private static bool IsGL2Extension(string function) + + private static bool IsGL2Extension(string function) + { + return (function.EndsWith("ARB") || + function.EndsWith("EXT") || + function.EndsWith("ATI") || + function.EndsWith("NV") || + function.EndsWith("SUN") || + function.EndsWith("SUNX") || + function.EndsWith("SGI") || + function.EndsWith("SGIS") || + function.EndsWith("SGIX") || + function.EndsWith("MESA") || + function.EndsWith("3DFX") || + function.EndsWith("IBM") || + function.EndsWith("GREMEDY") || + function.EndsWith("HP") || + function.EndsWith("INTEL") || + function.EndsWith("PGI") || + function.EndsWith("INGR") || + function.EndsWith("APPLE") || + function.EndsWith("OML") || + function.EndsWith("I3D")); + } + + #endregion + } +}