Merged with gl3 branch.

This commit is contained in:
the_fiddler 2007-08-01 09:27:57 +00:00
parent 8f90c9d50f
commit 34e3e388c4
36 changed files with 2573 additions and 2080 deletions

View file

@ -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);
}
}
}

View file

@ -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<Bind.Structures.Enum> enums = new List<Bind.Structures.Enum>();
EnumCollection enums = new EnumCollection();
EnumCollection extEnums = new EnumCollection();
Dictionary<string, string> GLTypes = new Dictionary<string, string>();
Dictionary<string, string> CSTypes = new Dictionary<string, string>();
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)
/// <summary>
/// Translates the opengl return type to the equivalent C# type.
/// </summary>
/// <param name="d">The opengl function to translate.</param>
/// <remarks>
/// 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.
/// </remarks>
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
}
}

View file

@ -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<Bind.Structures.Delegate> delegates = new List<Bind.Structures.Delegate>();
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<string> words = new List<string>(
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<string, string> ReadTypeMap(System.IO.StreamReader sr)
public virtual Dictionary<string, string> ReadTypeMap(System.IO.StreamReader sr)
{
Console.WriteLine("Reading opengl types.");
Dictionary<string, string> GLTypes = new Dictionary<string, string>();
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<string, string> ReadCSTypeMap(System.IO.StreamReader sr)
public virtual Dictionary<string, string> ReadCSTypeMap(System.IO.StreamReader sr)
{
Dictionary<string, string> CSTypes = new Dictionary<string, string>();
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
}
}

View file

@ -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<string, string> 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<string, string> 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
}
}

12
Source/Bind/IBind.cs Normal file
View file

@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Bind
{
interface IBind
{
//ISpecReader SpecReader { get; }
void Process();
}
}

View file

@ -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<string, string> ReadTypeMap(StreamReader specFile);
Dictionary<string, string> ReadCSTypeMap(StreamReader specFile);
}
}

View file

@ -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<string, string> CSTypes);
void WriteEnums(BindStreamWriter sw, EnumCollection enums);
void WriteTypes(BindStreamWriter sw, Dictionary<string, string> CSTypes);
}
}

View file

@ -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<CodeMemberMethod> functions;
List<CodeTypeDelegate> 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.");
}
}
}
}

View file

@ -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")]

View file

@ -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,
}
}
}

View file

@ -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<CodeTypeDelegate> delegates, out List<CodeMemberMethod> functions)
public static List<CodeTypeDelegate> ReadFunctionSpecs(string file)
{
StreamReader sr = OpenSpecFile(file);
Console.WriteLine("Reading function specs from file: {0}", file);
List<CodeTypeDelegate> delegates = new List<CodeTypeDelegate>();
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<string> words = new List<string>(
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<CodeMemberField> 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<CodeMemberField> enums, CodeMemberField c)
public static bool ListContainsConstant(List<CodeMemberField> constants, CodeMemberField c)
{
foreach (CodeMemberField d in constants)
if (d.Name == c.Name)
return true;
return false;
}
#endregion
#region public static Dictionary<string, CodeTypeReference> ReadTypeMap(string file)
public static Dictionary<string, CodeTypeReference> ReadTypeMap(string file)
{
Dictionary<string, CodeTypeReference> map =
new Dictionary<string, CodeTypeReference>();
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
}
}

View file

@ -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
{
/// <summary>
/// No wrapper needed.
/// </summary>
None,
/// <summary>
/// Function takes bool parameter - C uses Int for bools, so we have to marshal.
/// </summary>
BoolParameter,
/// <summary>
/// Function takes generic parameters - add ref/out generic and generic overloads.
/// </summary>
GenericParameter,
/// <summary>
/// Function takes arrays as parameters - add ref/out and ([Out]) array overloads.
/// </summary>
ArrayParameter,
/// <summary>
/// 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
/// </summary>
UncheckedParameter,
/// <summary>
/// Function that takes (in/ref/out) a naked pointer as a parameter - we pass an IntPtr.
/// </summary>
PointerParameter,
/// <summary>
/// Function returns string - needs manual marshalling through IntPtr to prevent the managed GC
/// from freeing memory allocated on the unmanaged side (e.g. glGetString).
/// </summary>
StringReturnValue,
/// <summary>
/// Function returns a void pointer - maps to IntPtr, and the user has to manually marshal the type.
/// </summary>
GenericReturnValue,
/// <summary>
/// Function returns a typed pointer - we have to copy the data to an array to protect it from the GC.
/// </summary>
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<string, CodeTypeReference> _gl_types = SpecReader.ReadTypeMap("gl.tm");
public static Dictionary<string, CodeTypeReference> GLTypes
{
get { return SpecTranslator._gl_types; }
set { SpecTranslator._gl_types = value; }
}
#endregion
#region CS types dictionary
private static Dictionary<string, CodeTypeReference> _cs_types = SpecReader.ReadTypeMap("csharp.tm");
public static Dictionary<string, CodeTypeReference> CSTypes
{
get { return SpecTranslator._cs_types; }
set { SpecTranslator._cs_types = value; }
}
#endregion
#region GLX types dictionary
private static Dictionary<string, string> _glx_types;
public static Dictionary<string, string> GLXTypes
{
get { return _glx_types; }
set { _glx_types = value; }
}
#endregion
#region WGL types dictionary
private static Dictionary<string, string> _wgl_types;
public static Dictionary<string, string> WGLTypes
{
get { return _wgl_types; }
set { _wgl_types = value; }
}
#endregion
#endregion
#region public static List<CodeMemberMethod> TranslateDelegates(List<CodeTypeDelegate> delegates, CodeTypeDeclarationCollection enums)
public static List<CodeMemberMethod> TranslateDelegates(List<CodeTypeDelegate> delegates, CodeTypeDeclarationCollection enums)
{
List<CodeMemberMethod> functions = new List<CodeMemberMethod>();
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<CodeMemberMethod> CreateWrappers(CodeTypeDelegate d)
private static List<CodeMemberMethod> CreateWrappers(CodeTypeDelegate d)
{
List<CodeMemberMethod> wrappers = new List<CodeMemberMethod>();
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<CodeMemberMethod> 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<CodeMemberMethod> 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)
/// <summary>
/// Obtain an IntPtr to the reference passed by the user.
/// </summary>
/// <param name="f"></param>
/// <param name="index"></param>
/// <returns></returns>
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("<summary>", true));
f.Comments.Add(new CodeCommentStatement(" ", true));
f.Comments.Add(new CodeCommentStatement("</summary>", 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("<summary>", true));
f.Comments.Add(new CodeCommentStatement(" ", true));
f.Comments.Add(new CodeCommentStatement("</summary>", 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
}
}

View file

@ -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<T> : Comparer<T> where T : CodeTypeMember
internal class CodeTypeNameComparer<T> : Comparer<T> 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<CodeTypeDelegate> delegates,
List<CodeMemberMethod> 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<CodeMemberMethod>());
delegates.Sort(new CodeTypeNameComparer<CodeTypeDelegate>());
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>());
//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<CodeMemberMethod> functions, List<CodeMemberField> enums)
private static CodeTypeDeclaration GenerateGLClass(List<CodeMemberMethod> 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
/// <summary>
/// Specifies OpenGl's native library archive.
/// </summary>
/// <remarks>
/// Specifies opengl32.dll everywhere; will be mapped via .config for mono.
/// </remarks>
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<CodeTypeDelegate> delegates)
private static CodeTypeDeclaration GenerateDelegatesClass(List<CodeTypeDelegate> 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<CodeTypeDelegate> delegates)
private static CodeTypeDeclaration GenerateImportsClass(List<CodeTypeDelegate> 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
/// <summary>
/// A hack to create the C# code for a DllImported function;
/// CodeDom does not directly support static extern methods.
/// </summary>
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
}

View file

@ -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

View file

@ -7,10 +7,8 @@ using System;
using System.Collections.Generic;
using System.Text;
namespace OpenTK.OpenGL.Bind
namespace Bind.Structures
{
#region Constant class
/// <summary>
/// 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
/// </summary>
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;
/// <summary>
/// Gets or sets the value of the opengl constant (eg. 0x00000001).
/// </summary>
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
/// <summary>
@ -78,20 +107,24 @@ namespace OpenTK.OpenGL.Bind
#endregion
#region public string ToString()
#region public override string ToString()
/// <summary>
/// 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).
/// </summary>
/// <returns></returns>
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
}

View file

@ -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
{
/// <summary>
/// Represents an opengl function.
/// The return value, function name, function parameters and opengl version can be retrieved or set.
/// </summary>
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
/// <summary>
/// Gets the CLSCompliant property. True if the delegate is not CLSCompliant.
/// </summary>
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;
/// <summary>
/// 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.
/// </summary>
public bool NeedsWrapper
{
get { return _needs_wrapper; }
set { _needs_wrapper = value; }
}
#endregion
#region public virtual bool Unsafe
/// <summary>
/// True if the delegate must be declared as 'unsafe'.
/// </summary>
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();
/// <summary>
/// Gets or sets the return value of the opengl function.
/// </summary>
public Parameter ReturnType
{
get { return _return_type; }
set
{
_return_type = value;
}
}
#endregion
#region public string Name
string _name;
/// <summary>
/// Gets or sets the name of the opengl function.
/// </summary>
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;
/// <summary>
/// Defines the opengl version that introduced this function.
/// </summary>
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()
/// <summary>
/// Gets the string representing the full function declaration without decorations
/// (ie "void glClearColor(float red, float green, float blue, float alpha)"
/// </summary>
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<string, string> 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<Function> CreateWrappers(Dictionary<string, string> CSTypes)
public List<Function> CreateWrappers(Dictionary<string, string> CSTypes)
{
if (this.Name == "MapBuffer")
{
}
List<Function> wrappers = new List<Function>();
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<Function> wrappers)
protected static int index = 0;
/// <summary>
/// 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)"
/// </summary>
protected void WrapParameters(Function function, List<Function> wrappers, Dictionary<string, string> 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<string, string> CSTypes)
protected Function GenericWrapper(Function function, int index, Dictionary<string, string> 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<string, string> CSTypes)
protected Function ReferenceWrapper(Function function, int index, Dictionary<string, string> 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<string, string> CSTypes)
protected Function ArrayWrapper(Function function, int index, Dictionary<string, string> 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<string, string> CSTypes, bool wantCLSCompliance)
/// <summary>
/// Generates a body which calls the specified function, pinning all needed parameters.
/// </summary>
/// <param name="function"></param>
protected static FunctionBody GetBodyWithPins(Function function, Dictionary<string, string> 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<string, Delegate>
{
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));
}
}
}
}

View file

@ -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<string, Enum>
{
/*
public override string ToString()
{
StringBuilder sb = new StringBuilder();
foreach (Bind.Structures.Enum e in this.Values)
{
sb.AppendLine(e.ToString());
}
return sb.ToString();
}
*/
}
#endregion
}

View file

@ -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
/// <summary>
/// Represents an opengl function.
/// The return value, function name, function parameters and opengl version can be retrieved or set.
/// </summary>
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;
/// <summary>
/// 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.
/// </summary>
public bool NeedsWrapper
{
get { return _needs_wrapper; }
set { _needs_wrapper = value; }
}
#endregion
#region Return value property
string _return_value;
/// <summary>
/// Gets or sets the return value of the opengl function.
/// </summary>
public string ReturnValue
{
get { return _return_value; }
set { _return_value = value; }
}
#endregion
#region Name property
string _name;
/// <summary>
/// Gets or sets the name of the opengl function.
/// </summary>
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;
/// <summary>
/// Defines the opengl version that introduced this function.
/// </summary>
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
/// <summary>
/// Gets the string representing the full function declaration without decorations
/// (ie "void glClearColor(float red, float green, float blue, float alpha)"
/// </summary>
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<string, string> CSTypes)
#endregion
public Function GetCLSCompliantFunction(Dictionary<string, string> 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<string>
@ -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<string, List<Function>>
{
public void Add(Function f)
{
if (!this.ContainsKey(f.Extension))
{
this.Add(f.Extension, new List<Function>());
this[f.Extension].Add(f);
}
else
{
this[f.Extension].Add(f);
}
}
public void AddRange(IEnumerable<Function> functions)
{
foreach (Function f in functions)
{
this.Add(f);
}
}
}
}

View file

@ -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
/// </summary>
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<string, string> 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<string, string> CSTypes)
public string GetCLSCompliantType(Dictionary<string, string> 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()
/// <summary>
///
/// Gets the parameter declaration string.
/// </summary>
/// <returns>The parameter list of an opengl function in the form ( [parameters] )</returns>
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<string, string> CSTypes)
/// <summary>
/// Gets the parameter declaration string.
/// </summary>
/// <param name="getCLSCompliant">If true, all types will be replaced by their CLSCompliant C# equivalents</param>
/// <param name="CSTypes">The list of C# types equivalent to the OpenGL types.</param>
/// <returns>The parameter list of an opengl function in the form ( [parameters] )</returns>
public string ToString(bool taoCompatible, Dictionary<string, string> 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)
/// <summary>
/// Replaces all parameters that match the old_param with the new_param.
/// </summary>
/// <param name="old_param"></param>
/// <param name="new_param"></param>
/// <returns></returns>
/// <remarks>The PreviousType property is ignored in parameter matching, and is set to the previous type in case of replacement.</remarks>
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)
/// <summary>
/// Replaces the first parameter that matches old_param with new_param.
/// </summary>
/// <param name="old_param"></param>
/// <param name="new_param"></param>
/// <returns></returns>
/// <remarks>The PreviousType property is ignored in parameter matching, and is set to the previous type in case of replacement.</remarks>
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

231
Source/Bind/Utilities.cs Normal file
View file

@ -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
{
/// <summary>
/// No wrapper needed.
/// </summary>
None = 0,
/// <summary>
/// Function takes bool parameter - C uses Int for bools, so we have to marshal.
/// </summary>
BoolParameter,
/// <summary>
/// Function takes generic parameters - add ref/out generic and generic overloads.
/// </summary>
GenericParameter,
/// <summary>
/// Function takes arrays as parameters - add ref/out and ([Out]) array overloads.
/// </summary>
ArrayParameter,
/// <summary>
/// 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
/// </summary>
UncheckedParameter,
/// <summary>
/// Function that takes (in/ref/out) a naked pointer as a parameter - we pass an IntPtr.
/// </summary>
PointerParameter,
/// <summary>
/// Function returns string - needs manual marshalling through IntPtr to prevent the managed GC
/// from freeing memory allocated on the unmanaged side (e.g. glGetString).
/// </summary>
StringReturnType,
/// <summary>
/// Function returns a void pointer - maps to IntPtr, and the user has to manually marshal the type.
/// </summary>
GenericReturnType,
/// <summary>
/// Function returns a typed pointer - we have to copy the data to an array to protect it from the GC.
/// </summary>
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<string> Keywords = new List<string>(
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)
/// <summary>
/// Merges the given enum into the enum list. If an enum of the same name exists,
/// it merges their respective constants.
/// </summary>
/// <param name="enums"></param>
/// <param name="t"></param>
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)
/// <summary>
/// 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)
/// </summary>
/// <param name="s"></param>
/// <param name="t"></param>
/// <returns></returns>
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
}
}