From 3ff2b848e25b905673efc239a0e317ef54b45db0 Mon Sep 17 00:00:00 2001 From: the_fiddler Date: Fri, 20 Apr 2007 19:03:11 +0000 Subject: [PATCH] Synced with latest Tao.GlBindGen source. OpenTK.OpenGL.Bind now uses CodeDOM internally for code generation. Many bugfixes. Supports newest specs. --- Source/OpenGL/Bind/Main.cs | 83 +- Source/OpenGL/Bind/Properties/AssemblyInfo.cs | 4 +- Source/OpenGL/Bind/Settings.cs | 7 +- Source/OpenGL/Bind/SpecReader.cs | 416 +++++++++ Source/OpenGL/Bind/SpecTranslator.cs | 877 ++++++++++++++++++ Source/OpenGL/Bind/SpecWriter.cs | 337 +++++++ Source/OpenGL/Bind/TranslateSpecs.cs | 496 ---------- Source/OpenGL/Bind/WriteSpecs.cs | 457 --------- 8 files changed, 1683 insertions(+), 994 deletions(-) create mode 100644 Source/OpenGL/Bind/SpecReader.cs create mode 100644 Source/OpenGL/Bind/SpecTranslator.cs create mode 100644 Source/OpenGL/Bind/SpecWriter.cs delete mode 100644 Source/OpenGL/Bind/TranslateSpecs.cs delete mode 100644 Source/OpenGL/Bind/WriteSpecs.cs diff --git a/Source/OpenGL/Bind/Main.cs b/Source/OpenGL/Bind/Main.cs index 2ff81394..9b6ebb3b 100644 --- a/Source/OpenGL/Bind/Main.cs +++ b/Source/OpenGL/Bind/Main.cs @@ -1,7 +1,29 @@ #region License -//Copyright (c) 2006 Stephen Apostolopoulos -//See license.txt for license info -#endregion +/* +MIT License +Copyright ©2003-2006 Tao Framework Team +http://www.taoframework.com +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 using System; using System.Text; @@ -10,18 +32,19 @@ using System.Security; using System.Security.Permissions; using System.Threading; using System.Collections.Generic; -using System.Collections; +using System.CodeDom; -[assembly:CLSCompliant(true), FileIOPermission(SecurityAction.RequestMinimum, Unrestricted = true)] namespace OpenTK.OpenGL.Bind { static class MainClass { static void Main(string[] arguments) { - Console.WriteLine("{0} {1} by Stephen Apostolopoulos (stapostol@gmail.com)", - System.Reflection.Assembly.GetExecutingAssembly().GetName().Name, + 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(); #region Handle Arguments @@ -72,44 +95,28 @@ namespace OpenTK.OpenGL.Bind { long ticks = System.DateTime.Now.Ticks; - // GL binding generation. + List functions; + List delegates; + CodeTypeDeclarationCollection enums; + CodeTypeDeclarationCollection enums2; - Translation.GLTypes = SpecReader.ReadTypeMap("gl.tm"); - Translation.CSTypes = SpecReader.ReadTypeMap("csharp.tm"); + 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); - List wrappers; - List functions = SpecReader.ReadFunctionSpecs("gl.spec"); - Hashtable enums = SpecReader.ReadEnumSpecs("enum.spec"); - Hashtable enums2 = SpecReader.ReadEnumSpecs("enumext.spec"); - foreach (Enum e in enums2.Values) - if (!enums.ContainsKey(e.Name)) - enums.Add(e.Name, e); - else - { - foreach (Constant c in e.ConstantCollection.Values) - if (!((Enum)enums[e.Name]).ConstantCollection.ContainsKey(c.Name)) - ((Enum)enums[e.Name]).ConstantCollection.Add(c.Name, c); - } + functions = SpecTranslator.TranslateDelegates(delegates, enums); - Translation.TranslateFunctions(functions, enums, out wrappers); - Translation.TranslateEnums(enums); - - SpecWriter.WriteSpecs(Settings.OutputPath, Settings.GLClass, functions, wrappers, enums); - - //ContextWriter.WriteMainContext(Settings.OutputPath, "GLContext", Settings.GLClass, functions); - //ContextWriter.WriteDerivedContext(Settings.OutputPath, "WindowsContext", Settings.GLClass, functions, "1.0", "1.1"); - //ContextWriter.WriteDerivedContext(Settings.OutputPath, "WindowsVistaContext", Settings.GLClass, functions, "1.0", "1.1", "1.2", "1.3", "1.4"); - //ContextWriter.WriteDerivedContext(Settings.OutputPath, "X11Context", Settings.GLClass, functions, "1.0", "1.1", "1.2", "1.3", "1.4", "1.5", "2.0"); - - // GLX binding generation. - //Translation.GLXTypes = SpecReader.ReadTypeMap("glx.tm"); // Works semi-ok. - //List functions = SpecReader.ReadFunctionSpecs("glx.spec"); // Works ok! - //Hashtable enums = SpecReader.ReadEnumSpecs("glxenum.spec"); // Works ok! - //SpecWriter.WriteSpecs(Settings.OutputPath, "Glx", functions, null, enums); // Needs updating. + // Generate the code + SpecWriter.Generate(delegates, functions, enums); ticks = System.DateTime.Now.Ticks - ticks; Console.WriteLine("Bindings generated in {0} seconds.", ticks / (double)10000000.0); + Console.WriteLine(); + Console.WriteLine("Press enter to continue..."); + Console.ReadLine(); } catch (SecurityException e) { diff --git a/Source/OpenGL/Bind/Properties/AssemblyInfo.cs b/Source/OpenGL/Bind/Properties/AssemblyInfo.cs index 563de4ba..8781513f 100644 --- a/Source/OpenGL/Bind/Properties/AssemblyInfo.cs +++ b/Source/OpenGL/Bind/Properties/AssemblyInfo.cs @@ -29,5 +29,5 @@ using System.Runtime.InteropServices; // Build Number // Revision // -[assembly: AssemblyVersion("0.7.7.0")] -[assembly: AssemblyFileVersion("0.7.7.0")] +[assembly: AssemblyVersion("0.9.0.3")] +[assembly: AssemblyFileVersion("0.9.0.3")] diff --git a/Source/OpenGL/Bind/Settings.cs b/Source/OpenGL/Bind/Settings.cs index 5fde81b6..4faed692 100644 --- a/Source/OpenGL/Bind/Settings.cs +++ b/Source/OpenGL/Bind/Settings.cs @@ -13,7 +13,12 @@ namespace OpenTK.OpenGL.Bind { public static string InputPath = "..\\..\\..\\Source\\OpenGL\\Specifications"; public static string OutputPath = "..\\..\\..\\Source\\OpenGL\\OpenGL\\Bindings"; - public static string GLClass = "GL"; public static string OutputNamespace = "OpenTK.OpenGL"; + public static string GLClass = "GL"; + public static string WglClass = "Wgl"; + public static string GlxClass = "Glx"; + public static string GluClass = "Glu"; + + public static string GLFunctionPrepend = String.Empty; } } diff --git a/Source/OpenGL/Bind/SpecReader.cs b/Source/OpenGL/Bind/SpecReader.cs new file mode 100644 index 00000000..5d0bd127 --- /dev/null +++ b/Source/OpenGL/Bind/SpecReader.cs @@ -0,0 +1,416 @@ +#region License +/* +MIT License +Copyright ©2003-2006 Tao Framework Team +http://www.taoframework.com +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 + +using System; +using System.Collections.Generic; +using System.Text; +using System.IO; +using System.CodeDom; + +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")); + } + #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(); + + 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); + } + 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)); + + // Hack - discard Boolean enum, it fsucks up the fragile translation code ahead. + //if (!e.Name.Contains("Bool")) + SpecTranslator.Merge(enums, e); + } + } + 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/OpenGL/Bind/SpecTranslator.cs b/Source/OpenGL/Bind/SpecTranslator.cs new file mode 100644 index 00000000..5c872f27 --- /dev/null +++ b/Source/OpenGL/Bind/SpecTranslator.cs @@ -0,0 +1,877 @@ +#region License +/* +MIT License +Copyright ©2003-2006 Tao Framework Team +http://www.taoframework.com +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 + +using System; +using System.Collections.Generic; +using System.Text; +using System.Collections; +using System.CodeDom; + +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 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.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 == "BufferDataARB") + { + } + + // Translate each parameter of the function while checking for needed wrappers: + foreach (CodeParameterDeclarationExpression p in d.Parameters) + { + // Translate parameter type + if (Search(enums, p.Type.BaseType)) + { + p.Type.BaseType = "Enums." + p.Type.BaseType; + } + else if (GLTypes.TryGetValue(p.Type.BaseType, out s)) + { + if (s.BaseType == "GLenum" && d.UserData.Contains("Category")) + { + bool found = false; + // There is no enumerant with the needed name. Try to see if any of the generic enumerants + // (category: VERSION_1_1 etc) match the needed name. + foreach (CodeTypeDeclaration enumerant in enums) + { + if (enumerant.Name == (string)d.UserData["Category"]) + { + p.Type.BaseType = "Enums." + (string)d.UserData["Category"]; + found = true; + break; + } + } + + if (!found || p.Type.BaseType.ToLower().Contains("bool")) + { + p.Type.BaseType = s.BaseType; + } + } + 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 + { + 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; + // 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 + + private static bool Search(CodeTypeDeclarationCollection enums, string name) + { + foreach (CodeTypeDeclaration enumerant in enums) + { + if (enumerant.Name == name) + { + return true; + } + } + + return false; + } + + #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) + /// + /// This function is not working yet! How can we obtain a pinned IntPtr from a ref + /// without resorting to unsafe code? + /// + /// + /// + /// + 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"]; + 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.ToLower().Contains("object") && !p.Type.BaseType.ToLower().Contains("enums.") || + (p.Type.ArrayRank > 0 && !p.Type.BaseType.ToLower().Contains("string"))) + { + // 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()"); + 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.Add( + new CodeMethodReturnStatement( + new CodeMethodInvokeExpression( + new CodeTypeReferenceExpression("Delegates"), + "gl" + f.Name, + parameters + ) + ) + ); + } + else + { + m.TryStatements.Add( + new CodeMethodInvokeExpression( + new CodeTypeReferenceExpression("Delegates"), + "gl" + f.Name, + parameters + ) + ); + } + + + 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/OpenGL/Bind/SpecWriter.cs b/Source/OpenGL/Bind/SpecWriter.cs new file mode 100644 index 00000000..e1aac66c --- /dev/null +++ b/Source/OpenGL/Bind/SpecWriter.cs @@ -0,0 +1,337 @@ +#region License +/* +MIT License +Copyright ©2003-2006 Tao Framework Team +http://www.taoframework.com +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 + +using System; +using System.Collections.Generic; +using System.Text; +using System.IO; +using System.Runtime.InteropServices; +using System.CodeDom; + +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) + { + 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/OpenGL/Bind/TranslateSpecs.cs b/Source/OpenGL/Bind/TranslateSpecs.cs deleted file mode 100644 index 41498bb0..00000000 --- a/Source/OpenGL/Bind/TranslateSpecs.cs +++ /dev/null @@ -1,496 +0,0 @@ -#region License -//Copyright (c) 2006 Stephen Apostolopoulos -//See license.txt for license info -#endregion - -using System; -using System.Collections.Generic; -using System.Text; -using System.Collections; - -namespace OpenTK.OpenGL.Bind -{ - #region WrapperTypes enum - - public enum WrapperTypes - { - None, - VoidArray, - Array, - UncheckedParameter, - ReturnsString, - ReturnsVoidPointer, - } - - #endregion - - static class Translation - { - public static char[] Separators = { ' ', '\n', ',', '(', ')', ';', '#' }; - - #region Dictionaries - - static Dictionary parameter_names = new Dictionary(); - - #region GL types dictionary - - private static Dictionary _gl_types; - - public static Dictionary GLTypes - { - get { return Translation._gl_types; } - set { Translation._gl_types = value; } - } - - #endregion - - #region CS types dictionary - - private static Dictionary _cs_types; - - public static Dictionary CSTypes - { - get { return Translation._cs_types; } - set { Translation._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 Constructor - - static Translation() - { - // Names - parameter_names.Add("base", "@base"); - parameter_names.Add("object", "@object"); - parameter_names.Add("string", "@string"); - parameter_names.Add("ref", "reference"); - parameter_names.Add("params", "parameters"); - parameter_names.Add("in", "@in"); - parameter_names.Add("class", "@class"); - } - - #endregion - - #region Translate enums - - public static void TranslateEnums(System.Collections.Hashtable enums) - { - // Add missing enums. - { - Enum e = new Enum(); - Constant c; - e.Name = "SGIX_icc_texture"; - c = new Constant("RGB_ICC_SGIX", "0x8460"); e.ConstantCollection.Add(c.Name, c); - c = new Constant("RGBA_ICC_SGIX", "0x8461"); e.ConstantCollection.Add(c.Name, c); - c = new Constant("ALPHA_ICC_SGIX", "0x8462"); e.ConstantCollection.Add(c.Name, c); - c = new Constant("LUMINANCE_ICC_SGIX", "0x8463"); e.ConstantCollection.Add(c.Name, c); - c = new Constant("INTENSITY_ICC_SGIX", "0x8464"); e.ConstantCollection.Add(c.Name, c); - c = new Constant("LUMINANCE_ALPHA_ICC_SGIX", "0x8465"); e.ConstantCollection.Add(c.Name, c); - c = new Constant("R5_G6_B5_ICC_SGIX", "0x8466"); e.ConstantCollection.Add(c.Name, c); - c = new Constant("R5_G6_B5_A8_ICC_SGIX", "0x8467"); e.ConstantCollection.Add(c.Name, c); - c = new Constant("ALPHA16_ICC_SGIX", "0x8468"); e.ConstantCollection.Add(c.Name, c); - c = new Constant("LUMINANCE16_ICC_SGIX", "0x8469"); e.ConstantCollection.Add(c.Name, c); - c = new Constant("INTENSITY16_ICC_SGIX", "0x846A"); e.ConstantCollection.Add(c.Name, c); - c = new Constant("LUMINANCE16_ALPHA8_ICC_SGIX", "0x846B"); e.ConstantCollection.Add(c.Name, c); - - enums.Add(e.Name, e); - } - - // Translate enums. - foreach (Enum e in enums.Values) - { - if (Char.IsDigit(e.Name[0])) - e.Name = e.Name.Insert(0, "_"); - - if (e.Name == "Boolean") - continue; - - foreach (Constant c in e.ConstantCollection.Values) - { - // 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, "_"); - - // Prepend an '_' to the aliased value, if it starts with a number (e.g. DataType.4_BYTES -> DataType._4_BYTES) - if (c.Value.Contains(".") && Char.IsDigit(c.Value[c.Value.IndexOf('.') + 1])) - c.Value = c.Value.Insert(c.Value.IndexOf('.') + 1, "_"); - - // 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 group). - if (!c.Value.Contains(".") && !c.Value.StartsWith("0x") && !Char.IsDigit(c.Value[0])) - { - if (c.Value.StartsWith("GL_")) - c.Value = c.Value.TrimStart('G', 'L', '_'); - - if (Char.IsDigit(c.Value[0])) - c.Value = c.Value.Insert(0, "_"); - - foreach (Enum search_enum in enums.Values) - foreach (Constant search_constant in search_enum.ConstantCollection.Values) - if (search_constant.Name == c.Value || search_constant.Name == c.Value.TrimStart('_')) - c.Value = c.Value.Insert(0, search_enum.Name + "."); - } - - // Handle enum.spec bugs: - if (c.Value.Contains("LightProperty")) - c.Value = c.Value.Replace("LightProperty", "LightParameter"); - } - } - - - } - - #endregion - - #region Translate functions - - public static void TranslateFunctions(List functions, Hashtable enums, out List wrappers) - { - foreach (Function f in functions) - { - TranslateReturnValue(f, enums); - TranslateParameters(f, enums); - - if (f.NeedsWrapper) - f.Name = f.Name + "_"; - } - - wrappers = GenerateWrappers(functions); - } - - #region Translate return value - - private static void TranslateReturnValue(Function f, Hashtable enums) - { - string s; - - if (f.ReturnValue == "void") - return; - - if (GLTypes.TryGetValue(f.ReturnValue, out s)) - f.ReturnValue = s; - - if (f.ReturnValue == "void[]") - { - f.NeedsWrapper = true; - f.WrapperType = WrapperTypes.ReturnsVoidPointer; - f.ReturnValue = "IntPtr"; - } - - if (f.ReturnValue == "GLstring") - { - f.NeedsWrapper = true; - f.WrapperType = WrapperTypes.ReturnsString; - f.ReturnValue = "IntPtr"; - } - } - - #endregion - - #region Translate parameters - - private static void TranslateParameters(Function f, Hashtable enums) - { - string s; - - foreach (Parameter p in f.Parameters) // Translate each parameter of the function, and check for needed wrappers. - { - #region Translate parameter name - - if (parameter_names.TryGetValue(p.Name, out s)) - p.Name = s; - - #endregion - - #region Translate parameter type - - //if (p.Type.Contains("Boolean")) - //{ - // p.Type = "GLboolean"; - //} - if (enums.ContainsKey(p.Type)) - { - p.Type = "Enums." + p.Type; - } - else if (p.Type == "GLenum") - { - if (enums.ContainsKey(f.Category)) - p.Type = "Enums." + f.Category; - } - else if (GLTypes.TryGetValue(p.Type, out s)) - p.Type = s; - - - #endregion - - #region Check for needed wrappers - - if (p.Type.Contains("ushort") && f.Name.Contains("LineStipple")) // glLineStipple needs wrapper to allow for unchecked mask values. - { - p.NeedsWrapper = true; - p.WrapperType = WrapperTypes.UncheckedParameter; - p.Unchecked = true; - } - else if (p.Array && p.Type.Contains("string")) // string parameters do not need special wrappers. - { - p.NeedsWrapper = false; - p.WrapperType = WrapperTypes.None; - } - else if (p.Array && p.Type.Contains("char")) // GLchar[] parameters should become (in) string or (out) StringBuilder - { - if (p.Flow == Parameter.FlowDirection.Out) - p.Type = "StringBuilder"; - else - p.Type = "string"; - p.Array = false; - } - else if (p.Array) // All other array parameters need wrappers (around IntPtr). - { - p.NeedsWrapper = true; - - if (p.Type.Contains("void")) - p.WrapperType = WrapperTypes.VoidArray; - else - p.WrapperType = WrapperTypes.Array; - - p.Type = "IntPtr"; - p.Array = false; // We do not want an array of IntPtrs (IntPtr[]) - it is the IntPtr that points to the array. - p.Flow = Parameter.FlowDirection.Undefined; // The same wrapper works for either in or out parameters. - } - - if (p.NeedsWrapper) // If there is at least 1 parameter that needs wrappers, mark the funcction for wrapping. - { - f.NeedsWrapper = true; - f.WrapperType = p.WrapperType; - } - - #endregion - } - } - - #endregion - - #region Generate wrappers - - private static List GenerateWrappers(List functions) - { - List wrappers = new List(); - Function w; - - foreach (Function f in functions) - { - if (f.NeedsWrapper) - { - if (f.WrapperType == WrapperTypes.UncheckedParameter) - { - w = new Function(f); - w.Name = w.Name.TrimEnd('_'); - - // Search and replace ushort parameters with ints. - Predicate is_ushort_parameter = new Predicate(delegate(Parameter p) { return p.Type == "GLushort"; }); - Parameter oldp = w.Parameters.Find(is_ushort_parameter); - Parameter newp = new Parameter(oldp); - newp.Type = "GLint"; - w.Parameters = w.Parameters.ReplaceAll(oldp, newp); - - // Call the low-level function wrapping (all parameters marked with Unchecked will automatically - // be decorated with the unchecked keyword). - w.Body.Add((f.ReturnValue.Contains("void") ? "" : "return ") + f.CallString() + ";"); - - // Add the wrapper. - wrappers.Add(w); - - continue; - } - - if (f.WrapperType == WrapperTypes.ReturnsString) - { - w = new Function(f); - w.Name = w.Name.TrimEnd('_'); - - // Replace the IntPtr return value with string. - w.ReturnValue = "string"; - - // Wrap the call to the low-level function (marshal the IntPtr to string). - w.Body.Add("return Marshal.PtrToStringAnsi(" + f.CallString() + ");"); - - // Add the wrapper. - wrappers.Add(w); - - continue; - } - - //if ( - WrapPointers(f, wrappers); - count = 0; - } - } - - return wrappers; - } - - static int count = 0; - private static void WrapPointers(Function f, List wrappers) - { - if (count == 0) - { - wrappers.Add(IntPtrToIntPtr(f)); - } - - if (count >= 0 && count < f.Parameters.Count) - { - if (f.Parameters[count].NeedsWrapper) - { - ++count; - WrapPointers(f, wrappers); - --count; - - Function w = IntPtrToObject(f, count); - wrappers.Add(w); - - ++count; - WrapPointers(w, wrappers); - --count; - - if (f.Parameters[count].WrapperType == WrapperTypes.Array) - { - w = IntPtrToArray(f, count); - wrappers.Add(w); - - ++count; - WrapPointers(w, wrappers); - --count; - } - } - else - { - ++count; - WrapPointers(f, wrappers); - --count; - } - } - } - - // IntPtr -> IntPtr wrapper. - private static Function IntPtrToIntPtr(Function f) - { - Function w = new Function(f); - w.Name = w.Name.TrimEnd('_'); - - w.Body.Add((f.ReturnValue.Contains("void") ? "" : "return ") + f.CallString() + ";"); - return w; - } - - // IntPtr -> object wrapper. - private static Function IntPtrToObject(Function f, int index) - { - Function w = new Function(f); - w.Name = w.Name.TrimEnd('_'); - - Parameter newp = new Parameter(f.Parameters[index]); - newp.Type = "object"; - if (newp.Flow == Parameter.FlowDirection.Out) - newp.Flow = Parameter.FlowDirection.Undefined; - w.Parameters = w.Parameters.Replace(f.Parameters[index], newp); - - // In the function body we should pin all objects in memory before calling the - // low-level function. - w.Body = GenerateBodyForPins(w); - - return w; - } - - // IntPtr -> GL[...] wrapper. - private static Function IntPtrToArray(Function f, int index) - { - Function w = new Function(f); - w.Name = w.Name.TrimEnd('_'); - - // Search and replace IntPtr parameters with the know parameter types: - Parameter newp = new Parameter(f.Parameters[index]); - newp.Type = f.Parameters[index].PreviousType; - newp.Array = true; - w.Parameters = w.Parameters.Replace(f.Parameters[index], newp); - - // In the function body we should pin all objects in memory before calling the - // low-level function. - w.Body = GenerateBodyForPins(w); - - return w; - } - - private static FunctionBody GenerateBodyForPins(Function w) - { - - FunctionBody body = new FunctionBody(); - - int i = 0; - StringBuilder sb = new StringBuilder(); - sb.Append("("); - foreach (Parameter p in w.Parameters) - { - if (p.Type == "object" || p.Array && !p.Type.Contains("string")) // we should allow the default marshalling behavior for strings. - { - body.Add("GCHandle h" + i + " = GCHandle.Alloc(" + p.Name + ", GCHandleType.Pinned);"); - sb.Append("h" + i + ".AddrOfPinnedObject()" + ", "); - i++; - } - else - { - sb.Append(p.Name + ", "); - } - } - sb.Replace(", ", ")", sb.Length - 2, 2); - - body.Add("try"); - body.Add("{"); - body.Add( - " " + - (w.ReturnValue.Contains("void") ? "" : "return ") + - w.Name + "_" + - sb.ToString() + - ";"); - body.Add("}"); - body.Add("finally"); - body.Add("{"); - while (i > 0) - { - body.Add(" h" + --i + ".Free();"); - } - body.Add("}"); - - return body; - } - - #endregion - - #endregion - } -} diff --git a/Source/OpenGL/Bind/WriteSpecs.cs b/Source/OpenGL/Bind/WriteSpecs.cs deleted file mode 100644 index 7e26a46d..00000000 --- a/Source/OpenGL/Bind/WriteSpecs.cs +++ /dev/null @@ -1,457 +0,0 @@ -#region License -//Copyright (c) 2006 Stephen Apostolopoulos -//See license.txt for license info -#endregion - -using System; -using System.Collections.Generic; -using System.Text; -using System.IO; -using System.Runtime.InteropServices; -using System.Collections; - -namespace OpenTK.OpenGL.Bind -{ - static partial class SpecWriter - { - #region Write specs - - public static void WriteSpecs(string output_path, string class_name, List functions, List wrappers, Hashtable enums) - { - WriteEnumSpecs(output_path, class_name, enums); - WriteCoreFunctionSpecs(output_path, class_name, functions, wrappers); - WriteExtensionFunctionSpecs(output_path, class_name, functions, wrappers); - } - - #endregion - - #region Write extension function specs - - private static void WriteExtensionFunctionSpecs(string output_path, string class_name, List functions, List wrappers) - { - //string filename = Path.Combine(output_path, class_name + "Extensions.cs"); - - //if (!Directory.Exists(output_path)) - // Directory.CreateDirectory(output_path); - - //StreamWriter sw = new StreamWriter(filename, false); - - //Console.WriteLine("Writing {0} class to {1}", class_name, filename); - - //WriteLicense(sw); - //WriteUsingDirectives(sw); - - //sw.WriteLine("namespace {0}", Settings.OutputNamespace); - //sw.WriteLine("{"); - - //WriteTypes(sw); - - //sw.WriteLine(" static public partial class {0}", class_name); - //sw.WriteLine(" {"); - //sw.WriteLine(" static public class Extensions"); - //sw.WriteLine(" {"); - - //WriteExtensionFunctionSignatures(sw, functions); - //WriteExtensionFunctions(sw, functions); - //WriteExtensionWrappers(sw, wrappers); - - //sw.WriteLine(" }"); - //sw.WriteLine(" }"); - //sw.WriteLine("}"); - //sw.WriteLine(); - - //sw.Flush(); - //sw.Close(); - } - - #endregion - - #region Write core function specs - - private static void WriteCoreFunctionSpecs(string output_path, string class_name, List functions, List wrappers) - { - string filename = Path.Combine(output_path, class_name + ".cs"); - - if (!Directory.Exists(output_path)) - Directory.CreateDirectory(output_path); - - StreamWriter sw = new StreamWriter(filename, false); - - Console.WriteLine("Writing {0} class to {1}", class_name, filename); - - WriteLicense(sw); - WriteUsingDirectives(sw); - - WriteTypes(sw); - - sw.WriteLine("namespace {0}", Settings.OutputNamespace); - sw.WriteLine("{"); - sw.WriteLine(" static public partial class {0}", class_name); - sw.WriteLine(" {"); - - WriteCoreFunctionSignatures(sw, functions); - WriteDllImports(sw, functions); - WriteCoreFunctions(sw, functions); - WriteCoreWrappers(sw, wrappers); - WriteCoreConstructor(sw, class_name, functions); - - sw.WriteLine(" }"); - - sw.WriteLine("}"); - sw.WriteLine(); - - sw.Flush(); - sw.Close(); - } - - #endregion - - #region Write enum specs - - private static void WriteEnumSpecs(string output_path, string class_name, Hashtable enums) - { - string filename = Path.Combine(output_path, class_name + "Enums.cs"); - - if (!Directory.Exists(output_path)) - Directory.CreateDirectory(output_path); - - StreamWriter sw = new StreamWriter(filename, false); - - Console.WriteLine("Writing {0} class to {1}", class_name, filename); - - WriteLicense(sw); - WriteUsingDirectives(sw); - - sw.WriteLine("namespace {0}", Settings.OutputNamespace); - sw.WriteLine("{"); - - WriteTypes(sw); - WriteEnums(sw, enums); - - sw.WriteLine("}"); - sw.WriteLine(); - - sw.Flush(); - sw.Close(); - } - - #endregion - - #region Write license - - public static void WriteLicense(StreamWriter sw) - { - sw.WriteLine("#region License"); - sw.WriteLine("//THIS FILE IS AUTOMATICALLY GENERATED"); - sw.WriteLine("//DO NOT EDIT BY HAND!!"); - sw.WriteLine("//See license.txt for license info"); - sw.WriteLine("#endregion"); - sw.WriteLine(); - } - - #endregion - - #region Write using directivers - - private static void WriteUsingDirectives(StreamWriter sw) - { - sw.WriteLine("using System;"); - sw.WriteLine("using System.Runtime.InteropServices;"); - sw.WriteLine("using System.Text;"); - sw.WriteLine(); - } - - #endregion - - #region Write types - - private static void WriteTypes(StreamWriter sw) - { - sw.WriteLine(" #region Types"); - //foreach ( c in constants) - foreach (string key in Translation.CSTypes.Keys) - { - sw.WriteLine(" using {0} = System.{1};", key, Translation.CSTypes[key]); - //sw.WriteLine(" public const {0};", c.ToString()); - } - sw.WriteLine(" #endregion"); - sw.WriteLine(); - } - - #endregion - - #region Write enums - - private static void WriteEnums(StreamWriter sw, Hashtable enums) - { - sw.WriteLine(" #region Enums"); - sw.WriteLine(" public struct Enums"); - sw.WriteLine(" {"); - - foreach (Enum e in enums.Values) - { - sw.WriteLine(e.ToString()); - } - - sw.WriteLine(" }"); - sw.WriteLine(" #endregion"); - sw.WriteLine(); - } - - #endregion - - #region Write core function signatures - - private static void WriteCoreFunctionSignatures(StreamWriter sw, List functions) - { - sw.WriteLine(" #region Function signatures"); - sw.WriteLine(); - sw.WriteLine(" public static class Delegates"); - sw.WriteLine(" {"); - - foreach (Function f in functions) - { - if (f.Extension) - continue; - sw.WriteLine(" public delegate {0};", f.ToString()); - } - - sw.WriteLine(" }"); - sw.WriteLine(" #endregion"); - sw.WriteLine(); - } - - #endregion - - #region Write core dll imports - - private static void WriteDllImports(StreamWriter sw, List functions) - { - sw.WriteLine(" #region Imports"); - sw.WriteLine(); - sw.WriteLine(" internal class Imports"); - sw.WriteLine(" {"); - - foreach (Function f in functions) - { - if (!f.Extension) - { - sw.WriteLine(" [DllImport(\"opengl32.dll\", EntryPoint = \"gl{0}\")]", f.Name.TrimEnd('_')); - sw.WriteLine(" public static extern {0};", f.ToString()); - } - } - - sw.WriteLine(" }"); - sw.WriteLine(" #endregion"); - sw.WriteLine(); - } - - #endregion - - #region Write core functions - - private static void WriteCoreFunctions(StreamWriter sw, List functions) - { - sw.WriteLine(" #region Static Functions (and static initialisation)"); - sw.WriteLine(); - - foreach (Function f in functions) - { - if (f.Extension) - continue; - sw.WriteLine(" public static Delegates.{0} {0} = new Delegates.{0}(Imports.{0});", f.Name); - } - - sw.WriteLine(); - sw.WriteLine(" #endregion"); - sw.WriteLine(); - } - - #endregion - - #region Write core wrappers - - public static void WriteCoreWrappers(StreamWriter sw, List wrappers) - { - sw.WriteLine(" #region Wrappers"); - sw.WriteLine(); - - if (wrappers != null) - { - foreach (Function f in wrappers) - { - if (f.Extension) - continue; - - sw.WriteLine(" #region {0}{1}", f.Name, f.Parameters.ToString()); - sw.WriteLine(); - - sw.WriteLine(" public static"); - sw.WriteLine(f.ToString(" ")); - - sw.WriteLine(" #endregion"); - sw.WriteLine(); - } - } - - sw.WriteLine(" #endregion"); - sw.WriteLine(); - } - - #endregion - - #region Write core constructor - - private static void WriteCoreConstructor(StreamWriter sw, string class_name, List functions) - { - sw.WriteLine(" #region static Constructor"); - sw.WriteLine(); - sw.WriteLine(" static {0}()", class_name); - sw.WriteLine(" {"); - - List import_list = new List(); - - #region Older Windows Core - - // Load core for older windows versions. - sw.WriteLine(" if (Environment.OSVersion.Platform == PlatformID.Win32NT && Environment.OSVersion.Version.Major < 6 || Environment.OSVersion.Platform == PlatformID.Win32Windows)"); - sw.WriteLine(" {"); - sw.WriteLine(" #region Older Windows Core"); - import_list.Add("1.2"); - import_list.Add("1.3"); - import_list.Add("1.4"); - import_list.Add("1.5"); - import_list.Add("2.0"); - import_list.Add("2.1"); - foreach (Function f in functions) - { - if (!f.Extension) - if (import_list.Contains(f.Version)) - sw.WriteLine(" {0} = (Delegates.{0})WindowsGetAddress(\"{1}\", typeof(Delegates.{0}));", f.Name, "gl"+ f.Name.TrimEnd('_')); - } - sw.WriteLine(" #endregion Older Windows Core"); - sw.WriteLine(" }"); - - #endregion - - #region Windows Vista Core - - // Load core for windows vista. - sw.WriteLine(" else if (Environment.OSVersion.Platform == PlatformID.Win32NT && Environment.OSVersion.Version.Major >= 6)"); - sw.WriteLine(" {"); - sw.WriteLine(" #region Windows Vista Core"); - import_list.Remove("1.2"); - import_list.Remove("1.3"); - import_list.Remove("1.4"); - foreach (Function f in functions) - { - if (!f.Extension) - if (import_list.Contains(f.Version)) - sw.WriteLine(" {0} = (Delegates.{0})WindowsGetAddress(\"{1}\", typeof(Delegates.{0}));", f.Name, "gl" + f.Name.TrimEnd('_')); - } - sw.WriteLine(" #endregion Windows Vista Core"); - sw.WriteLine(" }"); - - #endregion - - #region X11 Core - - // Load core for windows X11. - sw.WriteLine(" else if (Environment.OSVersion.Platform == PlatformID.Unix)"); - sw.WriteLine(" {"); - sw.WriteLine(" #region X11 Core"); - import_list.Remove("1.5"); - import_list.Remove("1.6"); - import_list.Remove("2.0"); - import_list.Remove("2.1"); - foreach (Function f in functions) - { - if (!f.Extension) - if (import_list.Contains(f.Version)) - sw.WriteLine(" {0} = (Delegates.{0})WindowsGetAddress(\"{1}\", typeof(Delegates.{0}));", f.Name, "gl" + f.Name.TrimEnd('_')); - } - sw.WriteLine(" #endregion X11 Core"); - sw.WriteLine(" }"); - - #endregion - - sw.WriteLine(" }"); - sw.WriteLine(" #endregion static Constructor"); - } - - #endregion - - #region Write extension function signatures - - private static void WriteExtensionFunctionSignatures(StreamWriter sw, List functions) - { - sw.WriteLine(" #region Function signatures"); - sw.WriteLine(); - sw.WriteLine(" public static class Delegates"); - sw.WriteLine(" {"); - - foreach (Function f in functions) - { - if (f.Extension) - sw.WriteLine(" public delegate {0};", f.ToString()); - } - - sw.WriteLine(" }"); - sw.WriteLine(" #endregion"); - sw.WriteLine(); - } - - #endregion - - #region Write extension functions - - private static void WriteExtensionFunctions(StreamWriter sw, List functions) - { - sw.WriteLine(" #region Static Functions (and static initialisation)"); - sw.WriteLine(); - - foreach (Function f in functions) - { - if (f.Extension) - sw.WriteLine(" public static Delegates.{0} {0} = new Delegates.{0}(Imports.{0});", f.Name); - } - - sw.WriteLine(); - sw.WriteLine(" #endregion"); - sw.WriteLine(); - } - - #endregion - - #region Write extension wrappers - - public static void WriteExtensionWrappers(StreamWriter sw, List wrappers) - { - sw.WriteLine(" #region Wrappers"); - sw.WriteLine(); - - if (wrappers != null) - { - foreach (Function w in wrappers) - { - if (!w.Extension) - continue; - - sw.WriteLine(" #region {0}{1}", w.Name, w.Parameters.ToString()); - sw.WriteLine(); - - sw.WriteLine(" public static"); - sw.WriteLine(w.ToString(" ")); - - sw.WriteLine(" #endregion"); - sw.WriteLine(); - } - } - - sw.WriteLine(" #endregion"); - } - - #endregion - - } -} \ No newline at end of file