public static GLParser FromFile(string xmlFile, params string[] Api) { XDocument file = XDocument.Load(xmlFile); GLParser spec = new GLParser(); spec.HeaderComment = file.Root.Element("comment").Value; foreach (var feature in file.Root.Elements("feature")) { var apiName = feature.Attribute("api").Value; if (Api.Contains(apiName)) { var version = new GLVersion { Api = feature.Attribute("api").Value.ToUpper(), Number = feature.Attribute("number").Value, }; version.Name = version.Api + version.Number.Replace(".", ""); // Add all enums and commands from previus versions int i = spec.Versions.Count - 1; if (i >= 0) { var previousVersion = spec.Versions[i]; foreach (var g in previousVersion.Groups) { version.Groups.Add(g.Clone()); } foreach (var c in previousVersion.Commands) { version.Commands.Add(c.Clone()); } } // Include all new enums and commands foreach (var require in feature.Elements("require")) { foreach (var enumElem in require.Elements("enum")) { var enumName = enumElem.Attribute("name").Value; // if enum doesn't exists bool exists = version.Groups.Exists(g => g.Enums.Exists(e => e.Name == enumName)); if (!exists) { // Find group string groupFound = FindGroupInXML(file, enumName); // The group already exists GlGroup glgroup = version.Groups.Find(g => g.Name == groupFound); if (glgroup == null) { glgroup = new GlGroup() { Name = groupFound }; version.Groups.Add(glgroup); } // Create new Enum var glEnum = new GLEnum(); glEnum.Initialize(file, enumName); glgroup.Enums.Add(glEnum); } } foreach (var commandElem in require.Elements("command")) { var glCommand = new GLCommand() { Name = commandElem.Attribute("name").Value }; if (version.Commands.Find(c => c.Name == glCommand.Name) == null) { // Create new command glCommand.Initialize(commandElem.Document); version.Commands.Add(glCommand); } } } // Add enum from commands foreach (var commandElem in version.Commands) { // Return Type if (commandElem.ReturnType.Type == "GLenum") { var selectedGroup = commandElem.ReturnType.Group; bool groupExists = version.Groups.Exists(g => g.Name == selectedGroup); if (!groupExists) { foreach (var group in file.Root.Element("groups").Elements("group")) { string groupName = group.Attribute("name").Value; if (groupName == selectedGroup) { GlGroup glgroup = new GlGroup() { Name = selectedGroup }; foreach (var e in group.Elements("enum")) { GLEnum glEnum = new GLEnum(); var enumName = e.Attribute("name").Value; glEnum.Initialize(file, enumName); glgroup.Enums.Add(glEnum); } version.Groups.Add(glgroup); } } } } // Parameters foreach (var param in commandElem.Parameters) { if (param.Type == "GLenum") { bool groupExists = version.Groups.Exists(g => g.Name == param.Group); if (!groupExists) { foreach (var group in file.Root.Element("groups").Elements("group")) { string groupName = group.Attribute("name").Value; if (groupName == param.Group) { GlGroup glgroup = new GlGroup() { Name = param.Group }; foreach (var e in group.Elements("enum")) { GLEnum glEnum = new GLEnum(); var enumName = e.Attribute("name").Value; glEnum.Initialize(file, enumName); glgroup.Enums.Add(glEnum); } version.Groups.Add(glgroup); } } } } } } // Remove any anums and commands foreach (var remove in feature.Elements("remove")) { foreach (var e in remove.Elements("enum")) { foreach (var group in version.Groups) { var glenum = group.Enums.Find(n => n.Name == e.Attribute("name").Value); if (glenum != null) { group.Enums.Remove(glenum); } } } foreach (var c in remove.Elements("command")) { version.Commands.RemoveAll(command => command.Name == c.Attribute("name").Value); } } // Remove all group with 0 enums version.Groups.RemoveAll(g => g.Enums.Count == 0); // Remove GLBoolean type version.Groups.RemoveAll(g => g.Name == "Boolean"); spec.Versions.Add(version); } } return(spec); }
private static void GenerateBindings(string glFile, DirectoryInfo workingDirectory, string[] api, string namespaceText, string nativeClassText) { var spec = GLParser.FromFile(glFile, api); // Select version var version = spec.Versions[spec.Versions.Count - 1]; // Write Enums using (var writer = new StreamWriter((Path.Combine(workingDirectory.FullName, "Enums.cs")))) { writer.WriteLine("using System;\n"); writer.WriteLine(namespaceText); writer.WriteLine("{"); int count = 0; foreach (var groupElem in version.Groups) { // Separate one line betweens enums if (count++ > 0) { writer.WriteLine(); } writer.WriteLine($"\tpublic enum {groupElem.Name} : uint"); writer.WriteLine("\t{"); foreach (var enumElem in groupElem.Enums) { if (IsUint(enumElem.Value)) { writer.WriteLine($"\t\t{enumElem.ShortName} = {enumElem.Value},"); } } writer.WriteLine("\t}"); } writer.WriteLine("}"); } // Write Commands using (var writer = new StreamWriter((Path.Combine(workingDirectory.FullName, $"{nativeClassText}.cs")))) { writer.WriteLine("using System;"); writer.WriteLine("using System.Runtime.InteropServices;\n"); writer.WriteLine(namespaceText); writer.WriteLine("{"); writer.WriteLine($"\tpublic static unsafe class {nativeClassText}"); writer.WriteLine("\t{"); writer.WriteLine("\t\tprivate static Func<string, IntPtr> s_getProcAddress;\n"); writer.WriteLine("\t\tprivate const CallingConvention CallConv = CallingConvention.Winapi;"); // Prototypes foreach (var command in version.Commands) { writer.WriteLine("\n\t\t[UnmanagedFunctionPointer(CallConv)]"); // Delegate StringBuilder delegateCommand = new StringBuilder("\t\tprivate delegate "); BuildReturnType(version, command, delegateCommand); delegateCommand.Append($" {command.Name}_t("); BuildParameterList(version, command, delegateCommand); delegateCommand.Append(");"); writer.WriteLine(delegateCommand.ToString()); // internal function writer.WriteLine($"\t\tprivate static {command.Name}_t p_{command.Name};"); // public function StringBuilder function = new StringBuilder($"\t\tpublic static "); BuildReturnType(version, command, function); function.Append($" {command.Name}("); BuildParameterList(version, command, function); function.Append($") => p_{command.Name}("); BuildParameterNamesList(command, function); function.Append(");"); writer.WriteLine(function.ToString()); } // Helper functions writer.WriteLine("\n\t\tpublic static void LoadGetString(Func<string, IntPtr> getProcAddress)"); writer.WriteLine("\t\t{"); writer.WriteLine("\t\t\ts_getProcAddress = getProcAddress;"); writer.WriteLine("\t\t\tLoadFunction(\"glGetString\", out p_glGetString);"); writer.WriteLine("\t\t}"); writer.WriteLine("\n\t\tpublic static void LoadAllFunctions(Func<string, IntPtr> getProcAddress)"); writer.WriteLine("\t\t{"); writer.WriteLine("\t\t\ts_getProcAddress = getProcAddress;\n"); foreach (var command in version.Commands) { writer.WriteLine($"\t\t\tLoadFunction(\"{command.Name}\", out p_{command.Name});"); } writer.WriteLine("\t\t}\n"); writer.WriteLine("\t\tprivate static void LoadFunction<T>(string name, out T field)"); writer.WriteLine("\t\t{"); writer.WriteLine("\t\t\tIntPtr funcPtr = s_getProcAddress(name);"); writer.WriteLine("\t\t\tif (funcPtr != IntPtr.Zero)"); writer.WriteLine("\t\t\t{"); writer.WriteLine("\t\t\t\tfield = Marshal.GetDelegateForFunctionPointer<T>(funcPtr);"); writer.WriteLine("\t\t\t}"); writer.WriteLine("\t\t\telse"); writer.WriteLine("\t\t\t{"); writer.WriteLine("\t\t\t\tfield = default(T);"); writer.WriteLine("\t\t\t}"); writer.WriteLine("\t\t}"); writer.WriteLine("\t}"); writer.WriteLine("}"); } }