Moved enum, constant, delegate and function transformations to EnumProcessor and FuncProcessor respectively.

Removed global enum, delegate and function collections.
Simplified loading process and removed global Initialize() methods.
Read "count" attributes for function parameters in overrides.xml.
Disabled wgl/glx/glu generators.
Removed large amounts of stale code.
This commit is contained in:
the_fiddler 2010-10-13 21:41:06 +00:00
parent 31b80891e2
commit 137818d10c
11 changed files with 736 additions and 1067 deletions

View file

@ -83,6 +83,8 @@ namespace Bind.ES
p.Name = param.GetAttribute("name", String.Empty);
string element_count = param.GetAttribute("elementcount", String.Empty);
if (String.IsNullOrEmpty(element_count))
element_count = param.GetAttribute("count", String.Empty);
if (!String.IsNullOrEmpty(element_count))
p.ElementCount = Int32.Parse(element_count);
@ -92,7 +94,7 @@ namespace Bind.ES
break;
}
}
d.Translate(overrides);
//d.Translate(overrides);
delegates.Add(d);
}
}
@ -188,9 +190,7 @@ namespace Bind.ES
}
Utilities.Merge(enums, all);
return new EnumProcessor(overrides).Process(enums);
//enums.Translate(overrides);
//return enums;
return enums;
}
}
}

View file

@ -28,14 +28,22 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Xml.XPath;
using Bind.Structures;
using Delegate = Bind.Structures.Delegate;
namespace Bind
{
class FuncProcessor
{
const string Path = "/overrides/replace/function[@name='{0}']";
{
const string Path = "/overrides/replace/function[@name='{0}' and @extension='{1}']";
static readonly Regex Endings =
new Regex(@"((((d|f|fi)|u?[isb])_?v?)|v)", RegexOptions.Compiled | RegexOptions.RightToLeft);
static readonly Regex EndingsNotToTrim =
new Regex("(ib|[tdrey]s|[eE]n[vd]|bled|Flag|Tess|Status|Pixels|Instanced|Indexed|Varyings|Boolean|IDs)", RegexOptions.Compiled | RegexOptions.RightToLeft);
static readonly Regex EndingsAddV = new Regex("^0", RegexOptions.Compiled);
XPathDocument Overrides { get; set; }
public FuncProcessor(XPathDocument overrides)
@ -45,5 +53,629 @@ namespace Bind
Overrides = overrides;
}
public FunctionCollection Process(DelegateCollection delegates, EnumCollection enums)
{
Console.WriteLine("Processing delegates.");
var nav = Overrides.CreateNavigator();
foreach (var d in delegates.Values)
{
TranslateReturnType(nav, d, enums);
TranslateParameters(nav, d, enums);
}
Console.WriteLine("Generating wrappers.");
var wrappers = CreateWrappers(delegates, enums);
Console.WriteLine("Creating CLS compliant overloads.");
wrappers = CreateCLSCompliantWrappers(wrappers, enums);
Console.WriteLine("Removing non-CLS compliant duplicates.");
return MarkCLSCompliance(wrappers);
}
// Trims unecessary suffices from the specified OpenGL function name.
static string TrimName(string name, bool keep_extension)
{
string trimmed_name = Utilities.StripGL2Extension(name);
string extension = Utilities.GetGL2Extension(name);
// Note: some endings should not be trimmed, for example: 'b' from Attrib.
// Check the endingsNotToTrim regex for details.
Match m = EndingsNotToTrim.Match(trimmed_name);
if ((m.Index + m.Length) != trimmed_name.Length)
{
m = Endings.Match(trimmed_name);
if (m.Length > 0 && m.Index + m.Length == trimmed_name.Length)
{
// Only trim endings, not internal matches.
if (m.Value[m.Length - 1] == 'v' && EndingsAddV.IsMatch(name) &&
!name.StartsWith("Get") && !name.StartsWith("MatrixIndex"))
{
// Only trim ending 'v' when there is a number
trimmed_name = trimmed_name.Substring(0, m.Index) + "v";
}
else
{
if (!trimmed_name.EndsWith("xedv"))
{
trimmed_name = trimmed_name.Substring(0, m.Index);
}
else
{
trimmed_name = trimmed_name.Substring(0, m.Index + 1);
}
}
}
}
return trimmed_name;
}
// Translates the opengl return type to the equivalent C# type.
//
// 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.
static void TranslateReturnType(XPathNavigator nav, Delegate d, EnumCollection enums)
{
string name = TrimName(d.Name, false);
string ext = d.Extension;
var function_override = nav.SelectSingleNode(String.Format(Path, name, ext));
if (function_override != null)
{
XPathNavigator return_override = function_override.SelectSingleNode("returns");
if (return_override != null)
{
d.ReturnType.CurrentType = return_override.Value;
}
}
d.ReturnType.Translate(nav, d.Category, enums);
if (d.ReturnType.CurrentType.ToLower().Contains("void") && d.ReturnType.Pointer != 0)
{
d.ReturnType.QualifiedType = "System.IntPtr";
d.ReturnType.WrapperType = WrapperTypes.GenericReturnType;
}
if (d.ReturnType.CurrentType.ToLower().Contains("string"))
{
d.ReturnType.QualifiedType = "System.IntPtr";
d.ReturnType.WrapperType = WrapperTypes.StringReturnType;
}
if (d.ReturnType.CurrentType.ToLower() == "object")
{
d.ReturnType.QualifiedType = "System.IntPtr";
d.ReturnType.WrapperType |= WrapperTypes.GenericReturnType;
}
if (d.ReturnType.CurrentType.Contains("GLenum"))
{
if ((Settings.Compatibility & Settings.Legacy.ConstIntEnums) == Settings.Legacy.None)
d.ReturnType.QualifiedType = String.Format("{0}.{1}", Settings.EnumsOutput, Settings.CompleteEnumName);
else
d.ReturnType.QualifiedType = "int";
}
d.ReturnType.CurrentType = d.ReturnType.GetCLSCompliantType();
}
static void TranslateParameters(XPathNavigator nav, Delegate d, EnumCollection enums)
{
string name = TrimName(d.Name, false);
string ext = d.Extension;
ext = String.IsNullOrEmpty(ext) ? "Core" : ext;
var function_override = nav.SelectSingleNode(String.Format(Path, name, ext));
for (int i = 0; i < d.Parameters.Count; i++)
{
if (function_override != null)
{
XPathNavigator param_override = function_override.SelectSingleNode(
String.Format("param[@name='{0}']", d.Parameters[i].Name));
if (param_override != null)
{
foreach (XPathNavigator node in param_override.SelectChildren(XPathNodeType.Element))
{
switch (node.Name)
{
case "type":
d.Parameters[i].CurrentType = (string)node.TypedValue;
break;
case "name":
d.Parameters[i].Name = (string)node.TypedValue;
break;
case "flow":
d.Parameters[i].Flow = Parameter.GetFlowDirection((string)node.TypedValue);
break;
}
}
}
}
d.Parameters[i].Translate(nav, d.Category, enums);
if (d.Parameters[i].CurrentType == "UInt16" && d.Name.Contains("LineStipple"))
d.Parameters[i].WrapperType = WrapperTypes.UncheckedParameter;
}
}
static FunctionCollection CreateWrappers(DelegateCollection delegates, EnumCollection enums)
{
var wrappers = new FunctionCollection();
foreach (var d in delegates.Values)
{
wrappers.AddRange(CreateNormalWrappers(d, enums));
}
return wrappers;
}
static FunctionCollection CreateCLSCompliantWrappers(FunctionCollection functions, EnumCollection enums)
{
// If the function is not CLS-compliant (e.g. it contains unsigned parameters)
// we need to create a CLS-Compliant overload. However, we should only do this
// iff the opengl function does not contain unsigned/signed overloads itself
// to avoid redefinitions.
var wrappers = new FunctionCollection();
foreach (var list in functions.Values)
{
foreach (var f in list)
{
wrappers.AddChecked(f);
if (!f.CLSCompliant)
{
Function cls = new Function(f);
cls.Body.Clear();
CreateBody(cls, true, enums);
bool modified = false;
for (int i = 0; i < f.Parameters.Count; i++)
{
cls.Parameters[i].CurrentType = cls.Parameters[i].GetCLSCompliantType();
if (cls.Parameters[i].CurrentType != f.Parameters[i].CurrentType)
modified = true;
}
if (modified)
wrappers.AddChecked(cls);
}
}
}
return wrappers;
}
static FunctionCollection MarkCLSCompliance(FunctionCollection collection)
{
//foreach (var w in
// (from list in collection
// from w1 in list.Value
// from w2 in list.Value
// where
// w1.TrimmedName == w2.TrimmedName &&
// w1.Parameters.Count == w2.Parameters.Count &&
// ParametersDifferOnlyInReference(w1.Parameters, w2.Parameters)
// select !w1.Parameters.HasReferenceParameters ? w1 : w2))
// {
// results.Add(w);
// }
foreach (List<Function> wrappers in collection.Values)
{
restart:
for (int i = 0; i < wrappers.Count; i++)
{
for (int j = i + 1; j < wrappers.Count; j++)
{
if (wrappers[i].TrimmedName == wrappers[j].TrimmedName && wrappers[i].Parameters.Count == wrappers[j].Parameters.Count)
{
bool function_i_is_problematic = false;
bool function_j_is_problematic = false;
int k;
for (k = 0; k < wrappers[i].Parameters.Count; k++)
{
if (wrappers[i].Parameters[k].CurrentType != wrappers[j].Parameters[k].CurrentType)
break;
if (wrappers[i].Parameters[k].DiffersOnlyOnReference(wrappers[j].Parameters[k]))
if (wrappers[i].Parameters[k].Reference)
function_i_is_problematic = true;
else
function_j_is_problematic = true;
}
if (k == wrappers[i].Parameters.Count)
{
if (function_i_is_problematic)
wrappers.RemoveAt(i);
//wrappers[i].CLSCompliant = false;
if (function_j_is_problematic)
wrappers.RemoveAt(j);
//wrappers[j].CLSCompliant = false;
if (function_i_is_problematic || function_j_is_problematic)
goto restart;
}
}
}
}
}
return collection;
}
static IEnumerable<Function> CreateNormalWrappers(Delegate d, EnumCollection enums)
{
Function f = new Function(d);
WrapReturnType(f);
foreach (var wrapper in WrapParameters(f, enums))
{
yield return wrapper;
}
}
public static IEnumerable<Function> WrapParameters(Function func, EnumCollection enums)
{
Function f;
if (func.Parameters.HasPointerParameters)
{
Function _this = new Function(func);
// Array overloads
foreach (Parameter p in _this.Parameters)
{
if (p.WrapperType == WrapperTypes.ArrayParameter && p.ElementCount != 1)
{
p.Reference = false;
p.Array++;
p.Pointer--;
}
}
f = new Function(_this);
CreateBody(f, false, enums);
yield return f;
foreach (var w in WrapVoidPointers(new Function(f), enums))
yield return w;
_this = new Function(func);
// Reference overloads
foreach (Parameter p in _this.Parameters)
{
if (p.WrapperType == WrapperTypes.ArrayParameter)
{
p.Reference = true;
p.Array--;
p.Pointer--;
}
}
f = new Function(_this);
CreateBody(f, false, enums);
yield return f;
foreach (var w in WrapVoidPointers(new Function(f), enums))
yield return w;
_this = func;
// Pointer overloads
// Should be last to work around Intellisense bug, where
// array overloads are not reported if there is a pointer overload.
foreach (Parameter p in _this.Parameters)
{
if (p.WrapperType == WrapperTypes.ArrayParameter)
{
p.Reference = false;
//p.Array--;
//p.Pointer++;
}
}
f = new Function(_this);
CreateBody(f, false, enums);
yield return f;
foreach (var w in WrapVoidPointers(new Function(f), enums))
yield return w;
}
else
{
f = new Function(func);
CreateBody(f, false, enums);
yield return f;
}
}
static int index;
static IEnumerable<Function> WrapVoidPointers(Function func, EnumCollection enums)
{
if (index >= 0 && index < func.Parameters.Count)
{
if (func.Parameters[index].WrapperType == WrapperTypes.GenericParameter)
{
// Recurse to the last parameter
++index;
foreach (var w in WrapVoidPointers(func, enums))
yield return w;
--index;
// On stack rewind, create generic wrappers
func.Parameters[index].Reference = true;
func.Parameters[index].Array = 0;
func.Parameters[index].Pointer = 0;
func.Parameters[index].Generic = true;
func.Parameters[index].CurrentType = "T" + index.ToString();
func.Parameters[index].Flow = FlowDirection.Undefined;
func.Parameters.Rebuild = true;
CreateBody(func, false, enums);
yield return new Function(func);
func.Parameters[index].Reference = false;
func.Parameters[index].Array = 1;
func.Parameters[index].Pointer = 0;
func.Parameters[index].Generic = true;
func.Parameters[index].CurrentType = "T" + index.ToString();
func.Parameters[index].Flow = FlowDirection.Undefined;
func.Parameters.Rebuild = true;
CreateBody(func, false, enums);
yield return new Function(func);
func.Parameters[index].Reference = false;
func.Parameters[index].Array = 2;
func.Parameters[index].Pointer = 0;
func.Parameters[index].Generic = true;
func.Parameters[index].CurrentType = "T" + index.ToString();
func.Parameters[index].Flow = FlowDirection.Undefined;
func.Parameters.Rebuild = true;
CreateBody(func, false, enums);
yield return new Function(func);
func.Parameters[index].Reference = false;
func.Parameters[index].Array = 3;
func.Parameters[index].Pointer = 0;
func.Parameters[index].Generic = true;
func.Parameters[index].CurrentType = "T" + index.ToString();
func.Parameters[index].Flow = FlowDirection.Undefined;
func.Parameters.Rebuild = true;
CreateBody(func, false, enums);
yield return new Function(func);
}
else
{
// Recurse to the last parameter
++index;
foreach (var w in WrapVoidPointers(func, enums))
yield return w;
--index;
}
}
}
static void WrapReturnType(Function func)
{
switch (func.ReturnType.WrapperType)
{
case WrapperTypes.StringReturnType:
func.ReturnType.QualifiedType = "String";
break;
}
}
readonly static List<string> handle_statements = new List<string>();
readonly static List<string> handle_release_statements = new List<string>();
readonly static List<string> fixed_statements = new List<string>();
readonly static List<string> assign_statements = new List<string>();
// For example, if parameter foo has indirection level = 1, then it
// is consumed as 'foo*' in the fixed_statements and the call string.
readonly static string[] indirection_levels = new string[] { "", "*", "**", "***", "****" };
static void CreateBody(Function func, bool wantCLSCompliance, EnumCollection enums)
{
Function f = new Function(func);
f.Body.Clear();
handle_statements.Clear();
handle_release_statements.Clear();
fixed_statements.Clear();
assign_statements.Clear();
// Obtain pointers by pinning the parameters
foreach (Parameter p in f.Parameters)
{
if (p.NeedsPin)
{
if (p.WrapperType == WrapperTypes.GenericParameter)
{
// 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.
handle_statements.Add(String.Format(
"{0} {1}_ptr = {0}.Alloc({1}, GCHandleType.Pinned);",
"GCHandle", p.Name));
handle_release_statements.Add(String.Format("{0}_ptr.Free();", p.Name));
// Due to the GCHandle-style pinning (which boxes value types), we need to assign the modified
// value back to the reference parameter (but only if it has an out or in/out flow direction).
if ((p.Flow == FlowDirection.Out || p.Flow == FlowDirection.Undefined) && p.Reference)
{
assign_statements.Add(String.Format(
"{0} = ({1}){0}_ptr.Target;",
p.Name, p.QualifiedType));
}
// Note! The following line modifies f.Parameters, *not* this.Parameters
p.Name = "(IntPtr)" + p.Name + "_ptr.AddrOfPinnedObject()";
}
else if (p.WrapperType == WrapperTypes.PointerParameter ||
p.WrapperType == WrapperTypes.ArrayParameter ||
p.WrapperType == WrapperTypes.ReferenceParameter)
{
// A fixed statement is issued for all non-generic pointers, arrays and references.
fixed_statements.Add(String.Format(
"fixed ({0}{3} {1} = {2})",
wantCLSCompliance && !p.CLSCompliant ? p.GetCLSCompliantType() : p.QualifiedType,
p.Name + "_ptr",
p.Array > 0 ? p.Name : "&" + p.Name,
indirection_levels[p.IndirectionLevel]));
if (p.Name == "pixels_ptr")
System.Diagnostics.Debugger.Break();
// Arrays are not value types, so we don't need to do anything for them.
// Pointers are passed directly by value, so we don't need to assign them back either (they don't change).
if ((p.Flow == FlowDirection.Out || p.Flow == FlowDirection.Undefined) && p.Reference)
{
assign_statements.Add(String.Format("{0} = *{0}_ptr;", p.Name));
}
p.Name = p.Name + "_ptr";
}
else
{
throw new ApplicationException("Unknown parameter type");
}
}
}
// Automatic OpenGL error checking.
// See OpenTK.Graphics.ErrorHelper for more information.
// Make sure that no error checking is added to the GetError function,
// as that would cause infinite recursion!
if ((Settings.Compatibility & Settings.Legacy.NoDebugHelpers) == 0)
{
if (f.TrimmedName != "GetError")
{
f.Body.Add("#if DEBUG");
f.Body.Add("using (new ErrorHelper(GraphicsContext.CurrentContext))");
f.Body.Add("{");
if (f.TrimmedName == "Begin")
f.Body.Add("GraphicsContext.CurrentContext.ErrorChecking = false;");
f.Body.Add("#endif");
}
}
if (!f.Unsafe && fixed_statements.Count > 0)
{
f.Body.Add("unsafe");
f.Body.Add("{");
f.Body.Indent();
}
if (fixed_statements.Count > 0)
{
f.Body.AddRange(fixed_statements);
f.Body.Add("{");
f.Body.Indent();
}
if (handle_statements.Count > 0)
{
f.Body.AddRange(handle_statements);
f.Body.Add("try");
f.Body.Add("{");
f.Body.Indent();
}
// Hack: When creating untyped enum wrappers, it is possible that the wrapper uses an "All"
// enum, while the delegate uses a specific enum (e.g. "TextureUnit"). For this reason, we need
// to modify the parameters before generating the call string.
// Note: We cannot generate a callstring using WrappedDelegate directly, as its parameters will
// typically be different than the parameters of the wrapper. We need to modify the parameters
// of the wrapper directly.
if ((Settings.Compatibility & Settings.Legacy.KeepUntypedEnums) != 0)
{
int parameter_index = -1; // Used for comparing wrapper parameters with delegate parameters
foreach (Parameter p in f.Parameters)
{
parameter_index++;
if (IsEnum(p.Name, enums) && p.QualifiedType != f.WrappedDelegate.Parameters[parameter_index].QualifiedType)
{
p.QualifiedType = f.WrappedDelegate.Parameters[parameter_index].QualifiedType;
}
}
}
if (assign_statements.Count > 0)
{
// Call function
string method_call = f.CallString();
if (f.ReturnType.CurrentType.ToLower().Contains("void"))
f.Body.Add(String.Format("{0};", method_call));
else if (func.ReturnType.CurrentType.ToLower().Contains("string"))
f.Body.Add(String.Format("{0} {1} = null; unsafe {{ {1} = new string((sbyte*){2}); }}",
func.ReturnType.QualifiedType, "retval", method_call));
else
f.Body.Add(String.Format("{0} {1} = {2};", f.ReturnType.QualifiedType, "retval", method_call));
// Assign out parameters
f.Body.AddRange(assign_statements);
// Return
if (!f.ReturnType.CurrentType.ToLower().Contains("void"))
{
f.Body.Add("return retval;");
}
}
else
{
// Call function and return
if (f.ReturnType.CurrentType.ToLower().Contains("void"))
f.Body.Add(String.Format("{0};", f.CallString()));
else if (func.ReturnType.CurrentType.ToLower().Contains("string"))
f.Body.Add(String.Format("unsafe {{ return new string((sbyte*){0}); }}",
f.CallString()));
else
f.Body.Add(String.Format("return {0};", f.CallString()));
}
// Free all allocated GCHandles
if (handle_statements.Count > 0)
{
f.Body.Unindent();
f.Body.Add("}");
f.Body.Add("finally");
f.Body.Add("{");
f.Body.Indent();
f.Body.AddRange(handle_release_statements);
f.Body.Unindent();
f.Body.Add("}");
}
if (!f.Unsafe && fixed_statements.Count > 0)
{
f.Body.Unindent();
f.Body.Add("}");
}
if (fixed_statements.Count > 0)
{
f.Body.Unindent();
f.Body.Add("}");
}
if ((Settings.Compatibility & Settings.Legacy.NoDebugHelpers) == 0)
{
if (f.TrimmedName != "GetError")
{
f.Body.Add("#if DEBUG");
if (f.TrimmedName == "End")
f.Body.Add("GraphicsContext.CurrentContext.ErrorChecking = true;");
f.Body.Add("}");
f.Body.Add("#endif");
}
}
func.Body = f.Body;
}
static bool IsEnum(string s, EnumCollection enums)
{
return enums.ContainsKey(s);
}
}
}

View file

@ -65,22 +65,16 @@ namespace Bind.GL2
public virtual void Process()
{
// Matches functions that cannot have their trailing 'v' trimmed for CLS-Compliance reasons.
// Built through trial and error :)
//Function.endingsAddV =
// new Regex(@"(Coord1|Attrib(I?)1(u?)|Stream1|Uniform2(u?)|(Point|Convolution|Transform|Sprite|List|Combiner|Tex)Parameter|Fog(Coord)?.*|VertexWeight|(Fragment)?Light(Model)?|Material|ReplacementCodeu?b?|Tex(Gen|Env)|Indexu?|TextureParameter.v)",
// RegexOptions.Compiled);
var overrides = new XPathDocument(Path.Combine(Settings.InputPath, functionOverridesFile));
Type.Initialize(glTypemap, csTypemap);
Enum.Initialize(enumSpec, enumSpecExt);
Enum.GLEnums.Translate(new XPathDocument(Path.Combine(Settings.InputPath, functionOverridesFile)));
Function.Initialize();
Delegate.Initialize(glSpec, glSpecExt);
var enums = ReadEnums(new StreamReader(Path.Combine(Settings.InputPath, enumSpec)));
var delegates = ReadDelegates(new StreamReader(Path.Combine(Settings.InputPath, glSpec)));
WriteBindings(
Delegate.Delegates,
Function.Wrappers,
Enum.GLEnums);
enums = new EnumProcessor(overrides).Process(enums);
var wrappers = new FuncProcessor(overrides).Process(delegates, enums);
WriteBindings(delegates, wrappers, enums);
}
#endregion
@ -171,8 +165,6 @@ namespace Bind.GL2
}
while (!specFile.EndOfStream);
d.Translate(function_overrides);
delegates.Add(d);
}
}
@ -454,7 +446,7 @@ namespace Bind.GL2
#region void WriteBindings
public void WriteBindings(DelegateCollection delegates, FunctionCollection functions, EnumCollection enums)
public void WriteBindings(DelegateCollection delegates, FunctionCollection wrappers, EnumCollection enums)
{
Console.WriteLine("Writing bindings to {0}", Settings.OutputPath);
if (!Directory.Exists(Settings.OutputPath))
@ -486,7 +478,7 @@ namespace Bind.GL2
sw.WriteLine("{");
sw.Indent();
WriteEnums(sw, Enum.GLEnums);
WriteEnums(sw, enums);
sw.Unindent();
if ((Settings.Compatibility & Settings.Legacy.NestedEnums) != Settings.Legacy.None)
@ -511,7 +503,7 @@ namespace Bind.GL2
sw.WriteLine("using System.Runtime.InteropServices;");
sw.WriteLine("#pragma warning disable 0649");
WriteDelegates(sw, Delegate.Delegates);
WriteDelegates(sw, delegates);
sw.Unindent();
sw.WriteLine("}");
@ -529,7 +521,7 @@ namespace Bind.GL2
sw.WriteLine("using System.Text;");
sw.WriteLine("using System.Runtime.InteropServices;");
WriteImports(sw, Delegate.Delegates);
WriteImports(sw, delegates);
sw.Unindent();
sw.WriteLine("}");
@ -547,7 +539,7 @@ namespace Bind.GL2
sw.WriteLine("using System.Text;");
sw.WriteLine("using System.Runtime.InteropServices;");
WriteWrappers(sw, Function.Wrappers, Type.CSTypes);
WriteWrappers(sw, wrappers, Type.CSTypes);
sw.Unindent();
sw.WriteLine("}");

View file

@ -4,6 +4,7 @@
*/
#endregion
using System;
using System.Diagnostics;
using Bind.Structures;
@ -51,19 +52,20 @@ namespace Bind.Glu
public override void Process()
{
Type.Initialize(glTypemap, csTypemap);
Enum.Initialize(enumSpec, enumSpecExt, enumSpecAux);
Function.Initialize();
Delegate.Initialize(glSpec, glSpecExt);
throw new NotSupportedException();
//Type.Initialize(glTypemap, csTypemap);
//Enum.Initialize(enumSpec, enumSpecExt, enumSpecAux);
//Function.Initialize();
//Delegate.Initialize(glSpec, glSpecExt);
// Process enums and delegates - create wrappers.
Trace.WriteLine("Processing specs, please wait...");
//this.Translate();
//// Process enums and delegates - create wrappers.
//Trace.WriteLine("Processing specs, please wait...");
////this.Translate();
WriteBindings(
Delegate.Delegates,
Function.Wrappers,
Enum.GLEnums);
//WriteBindings(
// Delegate.Delegates,
// Function.Wrappers,
// Enum.GLEnums);
}
}
}

View file

@ -4,6 +4,7 @@
*/
#endregion
using System;
using System.Diagnostics;
using Bind.Structures;
@ -48,19 +49,20 @@ namespace Bind.Glx
public override void Process()
{
Type.Initialize(glTypemap, csTypemap);
Enum.Initialize(enumSpec, enumSpecExt);
Function.Initialize();
Delegate.Initialize(glSpec, glSpecExt);
throw new NotSupportedException();
//Type.Initialize(glTypemap, csTypemap);
//Enum.Initialize(enumSpec, enumSpecExt);
//Function.Initialize();
//Delegate.Initialize(glSpec, glSpecExt);
// Process enums and delegates - create wrappers.
Trace.WriteLine("Processing specs, please wait...");
//this.Translate();
//// Process enums and delegates - create wrappers.
//Trace.WriteLine("Processing specs, please wait...");
////this.Translate();
WriteBindings(
Delegate.Delegates,
Function.Wrappers,
Enum.GLEnums);
//WriteBindings(
// Delegate.Delegates,
// Function.Wrappers,
// Enum.GLEnums);
}
}
}

View file

@ -19,9 +19,9 @@ namespace Bind.Structures
/// Represents an opengl function.
/// The return value, function name, function parameters and opengl version can be retrieved or set.
/// </summary>
public class Delegate : IComparable<Delegate>
class Delegate : IComparable<Delegate>
{
internal static DelegateCollection Delegates;
//internal static DelegateCollection Delegates;
private static bool delegatesLoaded;
bool? cls_compliance_overriden;
@ -36,14 +36,13 @@ namespace Bind.Structures
#region internal static void Initialize(string glSpec, string glSpecExt)
internal static void Initialize(string glSpec, string glSpecExt)
internal static DelegateCollection Initialize(string glSpec, string glSpecExt)
{
if (!delegatesLoaded)
{
DelegateCollection delegates = new DelegateCollection();
using (StreamReader sr = Utilities.OpenSpecFile(Settings.InputPath, glSpec))
{
Delegates = MainClass.Generator.ReadDelegates(sr);
delegates = MainClass.Generator.ReadDelegates(sr);
}
if (!String.IsNullOrEmpty(glSpecExt))
@ -52,14 +51,13 @@ namespace Bind.Structures
{
foreach (Delegate d in MainClass.Generator.ReadDelegates(sr).Values)
{
Utilities.Merge(Delegates, d);
Utilities.Merge(delegates, d);
}
}
}
Console.WriteLine("Enforcing CLS compliance.");
MarkCLSCompliance(Function.Wrappers);
delegatesLoaded = true;
}
return delegates;
}
#endregion
@ -261,8 +259,6 @@ namespace Bind.Structures
public string Extension
{
//get { return _extension; }
//set { _extension = value; }
get
{
if (!String.IsNullOrEmpty(Name))
@ -284,10 +280,9 @@ namespace Bind.Structures
#endregion
#region --- Strings ---
#region public string CallString()
/// <summary>
/// Returns a string that represents an invocation of this delegate.
/// </summary>
public string CallString()
{
StringBuilder sb = new StringBuilder();
@ -301,14 +296,10 @@ namespace Bind.Structures
return sb.ToString();
}
#endregion
/// <summary>
/// Returns a string representing the full non-delegate declaration without decorations.
/// (ie "(unsafe) void glXxxYyy(int a, float b, IntPtr c)"
/// </summary>
#region public string DeclarationString()
public string DeclarationString()
{
StringBuilder sb = new StringBuilder();
@ -322,10 +313,6 @@ namespace Bind.Structures
return sb.ToString();
}
#endregion
#region override public string ToString()
/// <summary>
/// Returns a string representing the full delegate declaration without decorations.
/// (ie "(unsafe) void delegate glXxxYyy(int a, float b, IntPtr c)"
@ -344,8 +331,6 @@ namespace Bind.Structures
return sb.ToString();
}
#endregion
public Delegate GetCLSCompliantDelegate()
{
Delegate f = new Delegate(this);
@ -360,286 +345,6 @@ namespace Bind.Structures
return f;
}
#endregion
#region --- Wrapper Creation ---
#region MarkCLSCompliance
static void MarkCLSCompliance(FunctionCollection collection)
{
foreach (List<Function> wrappers in Function.Wrappers.Values)
{
restart:
for (int i = 0; i < wrappers.Count; i++)
{
for (int j = i + 1; j < wrappers.Count; j++)
{
if (wrappers[i].TrimmedName == wrappers[j].TrimmedName && wrappers[i].Parameters.Count == wrappers[j].Parameters.Count)
{
bool function_i_is_problematic = false;
bool function_j_is_problematic = false;
int k;
for (k = 0; k < wrappers[i].Parameters.Count; k++)
{
if (wrappers[i].Parameters[k].CurrentType != wrappers[j].Parameters[k].CurrentType)
break;
if (wrappers[i].Parameters[k].DiffersOnlyOnReference(wrappers[j].Parameters[k]))
if (wrappers[i].Parameters[k].Reference)
function_i_is_problematic = true;
else
function_j_is_problematic = true;
}
if (k == wrappers[i].Parameters.Count)
{
if (function_i_is_problematic)
wrappers.RemoveAt(i);
//wrappers[i].CLSCompliant = false;
if (function_j_is_problematic)
wrappers.RemoveAt(j);
//wrappers[j].CLSCompliant = false;
if (function_i_is_problematic || function_j_is_problematic)
goto restart;
}
}
}
}
}
}
#endregion
#region CreateWrappers
void CreateWrappers()
{
List<Function> wrappers = new List<Function>();
CreateNormalWrappers(wrappers);
// Generate wrappers using the untyped enum parameters, if necessary.
if ((Settings.Compatibility & Settings.Legacy.KeepUntypedEnums) != 0)
{
CreateUntypedEnumWrappers(wrappers);
}
// Add CLS-compliant overloads for non-CLS compliant wrappers.
CreateCLSCompliantWrappers(wrappers);
}
private static void CreateCLSCompliantWrappers(List<Function> wrappers)
{
// If the function is not CLS-compliant (e.g. it contains unsigned parameters)
// we need to create a CLS-Compliant overload. However, we should only do this
// iff the opengl function does not contain unsigned/signed overloads itself
// to avoid redefinitions.
foreach (Function f in wrappers)
{
Function.Wrappers.AddChecked(f);
if (!f.CLSCompliant)
{
Function cls = new Function(f);
cls.Body.Clear();
cls.CreateBody(true);
bool modified = false;
for (int i = 0; i < f.Parameters.Count; i++)
{
cls.Parameters[i].CurrentType = cls.Parameters[i].GetCLSCompliantType();
if (cls.Parameters[i].CurrentType != f.Parameters[i].CurrentType)
modified = true;
}
if (modified)
Function.Wrappers.AddChecked(cls);
}
}
}
private void CreateUntypedEnumWrappers(List<Function> wrappers)
{
Function f = new Function(this);
var modified = false;
f.Parameters = new ParameterCollection(f.Parameters.Select(p =>
{
if (p.IsEnum && p.CurrentType != Settings.CompleteEnumName)
{
p.CurrentType = Settings.CompleteEnumName;
modified = true;
}
return p;
}));
if (modified)
{
f.WrapReturnType();
f.WrapParameters(wrappers);
}
}
void CreateNormalWrappers(List<Function> wrappers)
{
Function f = new Function(this);
f.WrapReturnType();
f.WrapParameters(wrappers);
}
#endregion
#region TrimName
// Trims unecessary suffices from the specified OpenGL function name.
protected static string TrimName(string name, bool keep_extension)
{
string trimmed_name = Utilities.StripGL2Extension(name);
string extension = Utilities.GetGL2Extension(name);
// Note: some endings should not be trimmed, for example: 'b' from Attrib.
// Check the endingsNotToTrim regex for details.
Match m = endingsNotToTrim.Match(trimmed_name);
if ((m.Index + m.Length) != trimmed_name.Length)
{
m = endings.Match(trimmed_name);
if (m.Length > 0 && m.Index + m.Length == trimmed_name.Length)
{
// Only trim endings, not internal matches.
if (m.Value[m.Length - 1] == 'v' && endingsAddV.IsMatch(name) &&
!name.StartsWith("Get") && !name.StartsWith("MatrixIndex"))
{
// Only trim ending 'v' when there is a number
trimmed_name = trimmed_name.Substring(0, m.Index) + "v";
}
else
{
if (!trimmed_name.EndsWith("xedv"))
trimmed_name = trimmed_name.Substring(0, m.Index);
else
trimmed_name = trimmed_name.Substring(0, m.Index + 1);
}
}
}
if (keep_extension)
return trimmed_name + extension;
else
return trimmed_name;
}
#endregion
#region TranslateReturnType
// Translates the opengl return type to the equivalent C# type.
//
// 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.
void TranslateReturnType(XPathNavigator overrides, XPathNavigator function_override)
{
if (function_override != null)
{
XPathNavigator return_override = function_override.SelectSingleNode("returns");
if (return_override != null)
{
ReturnType.CurrentType = return_override.Value;
}
}
ReturnType.Translate(overrides, Category);
if (ReturnType.CurrentType.ToLower().Contains("void") && ReturnType.Pointer != 0)
{
ReturnType.QualifiedType = "System.IntPtr";
ReturnType.WrapperType = WrapperTypes.GenericReturnType;
}
if (ReturnType.CurrentType.ToLower().Contains("string"))
{
ReturnType.QualifiedType = "System.IntPtr";
ReturnType.WrapperType = WrapperTypes.StringReturnType;
}
if (ReturnType.CurrentType.ToLower().Contains("object"))
{
ReturnType.QualifiedType = "System.IntPtr";
ReturnType.WrapperType |= WrapperTypes.GenericReturnType;
}
if (ReturnType.CurrentType.Contains("GLenum"))
{
if ((Settings.Compatibility & Settings.Legacy.ConstIntEnums) == Settings.Legacy.None)
ReturnType.QualifiedType = String.Format("{0}.{1}", Settings.EnumsOutput, Settings.CompleteEnumName);
else
ReturnType.QualifiedType = "int";
}
ReturnType.CurrentType = ReturnType.GetCLSCompliantType();
}
#endregion
#region TranslateParameters
protected virtual void TranslateParameters(XPathNavigator overrides, XPathNavigator function_override)
{
for (int i = 0; i < Parameters.Count; i++)
{
if (function_override != null)
{
XPathNavigator param_override = function_override.SelectSingleNode(String.Format("param[@name='{0}']", Parameters[i].Name));
if (param_override != null)
{
foreach (XPathNavigator node in param_override.SelectChildren(XPathNodeType.Element))
{
switch (node.Name)
{
case "type": Parameters[i].CurrentType = (string)node.TypedValue; break;
case "name": Parameters[i].Name = (string)node.TypedValue; break;
case "flow": Parameters[i].Flow = Parameter.GetFlowDirection((string)node.TypedValue); break;
}
}
}
}
Parameters[i].Translate(overrides, Category);
if (Parameters[i].CurrentType == "UInt16" && Name.Contains("LineStipple"))
Parameters[i].WrapperType = WrapperTypes.UncheckedParameter;
// Special case: these functions take a string[] that should stay as is.
// Todo: move to gloverrides.xml
//if (Name.Contains("ShaderSource") && Parameters[i].CurrentType.ToLower().Contains("string"))
// Parameters[i].Array = 1;
}
}
#endregion
internal void Translate(XPathDocument overrides)
{
if (overrides == null)
throw new ArgumentNullException("overrides");
string path = "/overrides/replace/function[@name='{0}' and @extension='{1}']";
string name = TrimName(Name, false);
XPathNavigator function_override = overrides.CreateNavigator().SelectSingleNode(String.Format(path, name, Extension));
TranslateReturnType(overrides.CreateNavigator(), function_override);
TranslateParameters(overrides.CreateNavigator(), function_override);
CreateWrappers();
}
#endregion
#region IComparable<Delegate> Members
public int CompareTo(Delegate other)

View file

@ -17,66 +17,10 @@ namespace Bind.Structures
public class Enum
{
internal static EnumCollection GLEnums = new EnumCollection();
internal static EnumCollection AuxEnums = new EnumCollection();
static StringBuilder translator = new StringBuilder();
string _name, _type;
static bool enumsLoaded;
#region Initialize
internal static void Initialize(string enumFile, string enumextFile, string auxFile)
{
Initialize(enumFile, enumextFile);
if (!String.IsNullOrEmpty(auxFile))
using (StreamReader sr = new StreamReader(Path.Combine(Settings.InputPath, auxFile)))
{
AuxEnums = MainClass.Generator.ReadEnums(sr);
}
}
internal static void Initialize(string enumFile, string enumextFile)
{
if (!enumsLoaded)
{
if (!String.IsNullOrEmpty(enumFile))
{
using (StreamReader sr = Utilities.OpenSpecFile(Settings.InputPath, enumFile))
{
GLEnums = MainClass.Generator.ReadEnums(sr);
}
}
if (!String.IsNullOrEmpty(enumextFile))
{
using (StreamReader sr = Utilities.OpenSpecFile(Settings.InputPath, enumextFile))
{
foreach (Enum e in MainClass.Generator.ReadEnums(sr).Values)
{
//enums.Add(e.Name, e);
Utilities.Merge(GLEnums, e);
}
}
}
enumsLoaded = true;
}
}
#endregion
#region Constructors
public Enum()
{
}
#endregion
#region Public Members
// Returns true if the enum contains a collection of flags, i.e. 1, 2, 4, 8, ...
public bool IsFlagCollection
{
@ -89,8 +33,6 @@ namespace Bind.Structures
}
}
#region public string Name
public string Name
{
get { return _name ?? ""; }
@ -104,10 +46,6 @@ namespace Bind.Structures
set { _type = value; }
}
#endregion
#region ConstantCollection
Dictionary<string, Constant> _constant_collection = new Dictionary<string, Constant>();
public IDictionary<string, Constant> ConstantCollection
@ -126,66 +64,6 @@ namespace Bind.Structures
}
}
#endregion
#region TranslateName
// Translate the constant's name to match .Net naming conventions
[Obsolete]
public static string TranslateName(string name)
{
if (String.IsNullOrEmpty(name))
return name;
if (Utilities.Keywords.Contains(name))
return name;
translator.Remove(0, translator.Length); // Trick to avoid allocating a new StringBuilder.
if ((Settings.Compatibility & Settings.Legacy.NoAdvancedEnumProcessing) == Settings.Legacy.None)
{
// Detect if we just passed a '_' or a number and make the next char uppercase.
bool is_after_underscore_or_number = true;
// Detect if previous character was uppercase, and turn the current one to lowercase.
bool is_previous_uppercase = false;
foreach (char c in name)
{
char char_to_add;
if (c == '_' || c == '-')
is_after_underscore_or_number = true;
else
{
if (Char.IsDigit(c))
is_after_underscore_or_number = true;
char_to_add = is_after_underscore_or_number ? Char.ToUpper(c) :
is_previous_uppercase ? Char.ToLower(c) : c;
translator.Append(char_to_add);
is_previous_uppercase = Char.IsUpper(c);
is_after_underscore_or_number = false;
}
}
translator[0] = Char.ToUpper(translator[0]);
}
else
translator.Append(name);
translator.Replace("Pname", "PName");
translator.Replace("SRgb", "Srgb");
string ret = translator.ToString();
if (ret.StartsWith(Settings.EnumPrefix))
return ret.Substring(Settings.EnumPrefix.Length);
return ret;
}
#endregion
#region ToString
public override string ToString()
{
StringBuilder sb = new StringBuilder();
@ -217,10 +95,6 @@ namespace Bind.Structures
return sb.ToString();
}
#endregion
#endregion
}
#endregion
@ -235,141 +109,6 @@ namespace Bind.Structures
Utilities.Merge(this, e);
}
[Obsolete]
internal void Translate(XPathDocument overrides)
{
if (overrides == null)
throw new ArgumentNullException("overrides");
string path = "/overrides/replace/enum[@name='{0}']";
// Translate enum names.
{
List<string> keys_to_update = new List<string>();
foreach (Enum e in Values)
{
string name = e.Name;
XPathNavigator enum_override = overrides.CreateNavigator().SelectSingleNode(String.Format(path, name));
if (enum_override != null)
{
XPathNavigator name_override = enum_override.SelectSingleNode("name");
if (name_override != null)
{
name = name_override.Value;
}
}
name = EnumProcessor.TranslateEnumName(name);
if (name != e.Name)
{
keys_to_update.Add(e.Name);
e.Name = name;
}
}
foreach (string name in keys_to_update)
{
Enum e = this[name];
Remove(name);
Add(e.Name, e);
}
keys_to_update = null;
}
foreach (Enum e in Values)
{
XPathNavigator enum_override = overrides.CreateNavigator().SelectSingleNode(String.Format(path, e.Name));
foreach (Constant c in e.ConstantCollection.Values)
{
if (enum_override != null)
{
XPathNavigator constant_override = enum_override.SelectSingleNode(String.Format("token[@name='{0}']", c.PreviousName)) ??
enum_override.SelectSingleNode(String.Format("token[@name={0}]", c.Name));
if (constant_override != null)
{
foreach (XPathNavigator node in constant_override.SelectChildren(XPathNodeType.Element))
{
switch (node.Name)
{
case "name": c.Name = (string)node.TypedValue; break;
case "value": c.Value = (string)node.TypedValue; break;
}
}
}
}
// 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 (Enum @enum in Values)
{
// Skip generic GLenum
if (@enum.Name == "GLenum")
continue;
if (@enum.ConstantCollection.ContainsKey(c.Value))
{
c.Reference = @enum.Name;
break;
}
}
}
}
}
foreach (Enum e in Values)
{
restart:
foreach (Constant c in e.ConstantCollection.Values)
{
bool result = Constant.TranslateConstantWithReference(c, Enum.GLEnums, Enum.AuxEnums);
if (!result)
{
e.ConstantCollection.Remove(c.Name);
goto restart;
}
}
}
if (Settings.DropMultipleTokens)
{
// When there are multiple tokens with the same value but different extension
// drop the duplicates. Order of preference: core > ARB > EXT > vendor specific
List<Constant> removed_tokens = new List<Constant>();
foreach (Enum e in Values)
{
if (e.Name == "All")
continue;
// This implementation is a not very bright O(n^2).
foreach (Constant c in e.ConstantCollection.Values)
{
foreach (Constant c2 in e.ConstantCollection.Values)
{
if (c.Name != c2.Name && c.Value == c2.Value)
{
int prefer = OrderOfPreference(Utilities.GetGL2Extension(c.Name), Utilities.GetGL2Extension(c2.Name));
if (prefer == -1)
removed_tokens.Add(c2);
else if (prefer == 1)
removed_tokens.Add(c);
}
}
}
foreach (Constant c in removed_tokens)
e.ConstantCollection.Remove(c.Name);
removed_tokens.Clear();
}
}
}
// Return -1 for ext1, 1 for ext2 or 0 if no preference.
int OrderOfPreference(string ext1, string ext2)
{

View file

@ -11,29 +11,8 @@ using System.Text.RegularExpressions;
namespace Bind.Structures
{
public class Function : Delegate, IEquatable<Function>, IComparable<Function>
class Function : Delegate, IEquatable<Function>, IComparable<Function>
{
#region Static Members
internal static FunctionCollection Wrappers;
static bool loaded;
#region internal static void Initialize()
internal static void Initialize()
{
if (!loaded)
{
Wrappers = new FunctionCollection();
loaded = true;
}
}
#endregion
#endregion
#region Fields
Delegate wrapped_delegate;
@ -239,369 +218,6 @@ namespace Bind.Structures
#endregion
#region public void WrapParameters(List<Function> wrappers)
public void WrapParameters(List<Function> wrappers)
{
Function f;
if (Parameters.HasPointerParameters)
{
Function _this = new Function(this);
// Array overloads
foreach (Parameter p in _this.Parameters)
{
if (p.WrapperType == WrapperTypes.ArrayParameter && p.ElementCount != 1)
{
p.Reference = false;
p.Array++;
p.Pointer--;
}
}
f = new Function(_this);
f.CreateBody(false);
wrappers.Add(f);
new Function(f).WrapVoidPointers(wrappers);
_this = new Function(this);
// Reference overloads
foreach (Parameter p in _this.Parameters)
{
if (p.WrapperType == WrapperTypes.ArrayParameter)
{
p.Reference = true;
p.Array--;
p.Pointer--;
}
}
f = new Function(_this);
f.CreateBody(false);
wrappers.Add(f);
new Function(f).WrapVoidPointers(wrappers);
_this = this;
// Pointer overloads
// Should be last to work around Intellisense bug, where
// array overloads are not reported if there is a pointer overload.
foreach (Parameter p in _this.Parameters)
{
if (p.WrapperType == WrapperTypes.ArrayParameter)
{
p.Reference = false;
//p.Array--;
//p.Pointer++;
}
}
f = new Function(_this);
f.CreateBody(false);
wrappers.Add(f);
new Function(f).WrapVoidPointers(wrappers);
}
else
{
f = new Function(this);
f.CreateBody(false);
wrappers.Add(f);
}
}
#endregion
#region public void WrapVoidPointers(List<Function> wrappers)
public void WrapVoidPointers(List<Function> wrappers)
{
if (index >= 0 && index < Parameters.Count)
{
if (Parameters[index].WrapperType == WrapperTypes.GenericParameter)
{
// Recurse to the last parameter
++index;
WrapVoidPointers(wrappers);
--index;
// On stack rewind, create generic wrappers
Parameters[index].Reference = true;
Parameters[index].Array = 0;
Parameters[index].Pointer = 0;
Parameters[index].Generic = true;
Parameters[index].CurrentType = "T" + index.ToString();
Parameters[index].Flow = FlowDirection.Undefined;
Parameters.Rebuild = true;
CreateBody(false);
wrappers.Add(new Function(this));
Parameters[index].Reference = false;
Parameters[index].Array = 1;
Parameters[index].Pointer = 0;
Parameters[index].Generic = true;
Parameters[index].CurrentType = "T" + index.ToString();
Parameters[index].Flow = FlowDirection.Undefined;
Parameters.Rebuild = true;
CreateBody(false);
wrappers.Add(new Function(this));
Parameters[index].Reference = false;
Parameters[index].Array = 2;
Parameters[index].Pointer = 0;
Parameters[index].Generic = true;
Parameters[index].CurrentType = "T" + index.ToString();
Parameters[index].Flow = FlowDirection.Undefined;
Parameters.Rebuild = true;
CreateBody(false);
wrappers.Add(new Function(this));
Parameters[index].Reference = false;
Parameters[index].Array = 3;
Parameters[index].Pointer = 0;
Parameters[index].Generic = true;
Parameters[index].CurrentType = "T" + index.ToString();
Parameters[index].Flow = FlowDirection.Undefined;
Parameters.Rebuild = true;
CreateBody(false);
wrappers.Add(new Function(this));
}
else
{
// Recurse to the last parameter
++index;
WrapVoidPointers(wrappers);
--index;
}
}
}
#endregion
#region public void WrapReturnType()
public void WrapReturnType()
{
switch (ReturnType.WrapperType)
{
case WrapperTypes.StringReturnType:
ReturnType.QualifiedType = "String";
break;
}
}
#endregion
#region public void CreateBody(bool wantCLSCompliance)
readonly static List<string> handle_statements = new List<string>();
readonly static List<string> handle_release_statements = new List<string>();
readonly static List<string> fixed_statements = new List<string>();
readonly static List<string> assign_statements = new List<string>();
// For example, if parameter foo has indirection level = 1, then it
// is consumed as 'foo*' in the fixed_statements and the call string.
string[] indirection_levels = new string[] { "", "*", "**", "***", "****" };
public void CreateBody(bool wantCLSCompliance)
{
Function f = new Function(this);
f.Body.Clear();
handle_statements.Clear();
handle_release_statements.Clear();
fixed_statements.Clear();
assign_statements.Clear();
// Obtain pointers by pinning the parameters
foreach (Parameter p in f.Parameters)
{
if (p.NeedsPin)
{
if (p.WrapperType == WrapperTypes.GenericParameter)
{
// 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.
handle_statements.Add(String.Format(
"{0} {1}_ptr = {0}.Alloc({1}, GCHandleType.Pinned);",
"GCHandle", p.Name));
handle_release_statements.Add(String.Format("{0}_ptr.Free();", p.Name));
// Due to the GCHandle-style pinning (which boxes value types), we need to assign the modified
// value back to the reference parameter (but only if it has an out or in/out flow direction).
if ((p.Flow == FlowDirection.Out || p.Flow == FlowDirection.Undefined) && p.Reference)
{
assign_statements.Add(String.Format(
"{0} = ({1}){0}_ptr.Target;",
p.Name, p.QualifiedType));
}
// Note! The following line modifies f.Parameters, *not* this.Parameters
p.Name = "(IntPtr)" + p.Name + "_ptr.AddrOfPinnedObject()";
}
else if (p.WrapperType == WrapperTypes.PointerParameter ||
p.WrapperType == WrapperTypes.ArrayParameter ||
p.WrapperType == WrapperTypes.ReferenceParameter)
{
// A fixed statement is issued for all non-generic pointers, arrays and references.
fixed_statements.Add(String.Format(
"fixed ({0}{3} {1} = {2})",
wantCLSCompliance && !p.CLSCompliant ? p.GetCLSCompliantType() : p.QualifiedType,
p.Name + "_ptr",
p.Array > 0 ? p.Name : "&" + p.Name,
indirection_levels[p.IndirectionLevel]));
if (p.Name == "pixels_ptr")
System.Diagnostics.Debugger.Break();
// Arrays are not value types, so we don't need to do anything for them.
// Pointers are passed directly by value, so we don't need to assign them back either (they don't change).
if ((p.Flow == FlowDirection.Out || p.Flow == FlowDirection.Undefined) && p.Reference)
{
assign_statements.Add(String.Format("{0} = *{0}_ptr;", p.Name));
}
p.Name = p.Name + "_ptr";
}
else
{
throw new ApplicationException("Unknown parameter type");
}
}
}
// Automatic OpenGL error checking.
// See OpenTK.Graphics.ErrorHelper for more information.
// Make sure that no error checking is added to the GetError function,
// as that would cause infinite recursion!
if ((Settings.Compatibility & Settings.Legacy.NoDebugHelpers) == 0)
{
if (f.TrimmedName != "GetError")
{
f.Body.Add("#if DEBUG");
f.Body.Add("using (new ErrorHelper(GraphicsContext.CurrentContext))");
f.Body.Add("{");
if (f.TrimmedName == "Begin")
f.Body.Add("GraphicsContext.CurrentContext.ErrorChecking = false;");
f.Body.Add("#endif");
}
}
if (!f.Unsafe && fixed_statements.Count > 0)
{
f.Body.Add("unsafe");
f.Body.Add("{");
f.Body.Indent();
}
if (fixed_statements.Count > 0)
{
f.Body.AddRange(fixed_statements);
f.Body.Add("{");
f.Body.Indent();
}
if (handle_statements.Count > 0)
{
f.Body.AddRange(handle_statements);
f.Body.Add("try");
f.Body.Add("{");
f.Body.Indent();
}
// Hack: When creating untyped enum wrappers, it is possible that the wrapper uses an "All"
// enum, while the delegate uses a specific enum (e.g. "TextureUnit"). For this reason, we need
// to modify the parameters before generating the call string.
// Note: We cannot generate a callstring using WrappedDelegate directly, as its parameters will
// typically be different than the parameters of the wrapper. We need to modify the parameters
// of the wrapper directly.
if ((Settings.Compatibility & Settings.Legacy.KeepUntypedEnums) != 0)
{
int parameter_index = -1; // Used for comparing wrapper parameters with delegate parameters
foreach (Parameter p in f.Parameters)
{
parameter_index++;
if (p.IsEnum && p.QualifiedType != f.WrappedDelegate.Parameters[parameter_index].QualifiedType)
{
p.QualifiedType = f.WrappedDelegate.Parameters[parameter_index].QualifiedType;
}
}
}
if (assign_statements.Count > 0)
{
// Call function
string method_call = f.CallString();
if (f.ReturnType.CurrentType.ToLower().Contains("void"))
f.Body.Add(String.Format("{0};", method_call));
else if (ReturnType.CurrentType.ToLower().Contains("string"))
f.Body.Add(String.Format("{0} {1} = null; unsafe {{ {1} = new string((sbyte*){2}); }}",
ReturnType.QualifiedType, "retval", method_call));
else
f.Body.Add(String.Format("{0} {1} = {2};", f.ReturnType.QualifiedType, "retval", method_call));
// Assign out parameters
f.Body.AddRange(assign_statements);
// Return
if (!f.ReturnType.CurrentType.ToLower().Contains("void"))
{
f.Body.Add("return retval;");
}
}
else
{
// Call function and return
if (f.ReturnType.CurrentType.ToLower().Contains("void"))
f.Body.Add(String.Format("{0};", f.CallString()));
else if (ReturnType.CurrentType.ToLower().Contains("string"))
f.Body.Add(String.Format("unsafe {{ return new string((sbyte*){0}); }}",
f.CallString()));
else
f.Body.Add(String.Format("return {0};", f.CallString()));
}
// Free all allocated GCHandles
if (handle_statements.Count > 0)
{
f.Body.Unindent();
f.Body.Add("}");
f.Body.Add("finally");
f.Body.Add("{");
f.Body.Indent();
f.Body.AddRange(handle_release_statements);
f.Body.Unindent();
f.Body.Add("}");
}
if (!f.Unsafe && fixed_statements.Count > 0)
{
f.Body.Unindent();
f.Body.Add("}");
}
if (fixed_statements.Count > 0)
{
f.Body.Unindent();
f.Body.Add("}");
}
if ((Settings.Compatibility & Settings.Legacy.NoDebugHelpers) == 0)
{
if (f.TrimmedName != "GetError")
{
f.Body.Add("#if DEBUG");
if (f.TrimmedName == "End")
f.Body.Add("GraphicsContext.CurrentContext.ErrorChecking = true;");
f.Body.Add("}");
f.Body.Add("#endif");
}
}
Body = f.Body;
}
#endregion
#region IComparable<Function> Members
public int CompareTo(Function other)
@ -712,27 +328,27 @@ namespace Bind.Structures
/// <param name="f">The Function to add.</param>
public void AddChecked(Function f)
{
if (Function.Wrappers.ContainsKey(f.Extension))
if (ContainsKey(f.Extension))
{
int index = Function.Wrappers[f.Extension].IndexOf(f);
int index = this[f.Extension].IndexOf(f);
if (index == -1)
{
Function.Wrappers.Add(f);
Add(f);
}
else
{
Function existing = Function.Wrappers[f.Extension][index];
Function existing = this[f.Extension][index];
if ((existing.Parameters.HasUnsignedParameters && !unsignedFunctions.IsMatch(existing.Name) && unsignedFunctions.IsMatch(f.Name)) ||
(!existing.Parameters.HasUnsignedParameters && unsignedFunctions.IsMatch(existing.Name) && !unsignedFunctions.IsMatch(f.Name)))
{
Function.Wrappers[f.Extension].RemoveAt(index);
Function.Wrappers[f.Extension].Add(f);
this[f.Extension].RemoveAt(index);
this[f.Extension].Add(f);
}
}
}
else
{
Function.Wrappers.Add(f);
Add(f);
}
}
}

View file

@ -281,11 +281,11 @@ namespace Bind.Structures
#endregion
#region override public void Translate(XPathNavigator overrides, string category)
#region Translate()
override public void Translate(XPathNavigator overrides, string category)
override public void Translate(XPathNavigator overrides, string category, EnumCollection enums)
{
base.Translate(overrides, category);
base.Translate(overrides, category, enums);
// Find out the necessary wrapper types.
if (Pointer != 0)/* || CurrentType == "IntPtr")*/

View file

@ -204,15 +204,15 @@ namespace Bind.Structures
#endregion
// Returns true if parameter is an enum.
public bool IsEnum
{
get
{
return Enum.GLEnums.ContainsKey(CurrentType) ||
Enum.AuxEnums.ContainsKey(CurrentType);
}
}
//// Returns true if parameter is an enum.
//public bool IsEnum
//{
// get
// {
// return Enum.GLEnums.ContainsKey(CurrentType) ||
// Enum.AuxEnums.ContainsKey(CurrentType);
// }
//}
#region IndirectionLevel
@ -351,32 +351,34 @@ namespace Bind.Structures
#region public virtual void Translate(XPathNavigator overrides, string category)
public virtual void Translate(XPathNavigator overrides, string category)
public virtual void Translate(XPathNavigator overrides, string category, EnumCollection enums)
{
Enum @enum;
string s;
// Try to find out if it is an enum. If the type exists in the normal GLEnums list, use this.
// Otherwise, try to find it in the aux enums list. If it exists in neither, it is not an enum.
// Special case for Boolean - it is an enum, but it is dumb to use that instead of the 'bool' type.
bool normal = false;
bool aux = false;
normal = Enum.GLEnums.TryGetValue(CurrentType, out @enum);
if (!normal)
aux = Enum.AuxEnums != null && Enum.AuxEnums.TryGetValue(CurrentType, out @enum);
bool normal = enums.TryGetValue(CurrentType, out @enum);
//bool aux = enums.TryGetValue(EnumProcessor.TranslateEnumName(CurrentType), out @enum);
// Translate enum types
if ((normal || aux) && @enum.Name != "GLenum" && @enum.Name != "Boolean")
if ((normal /*|| aux*/) && @enum.Name != "GLenum" && @enum.Name != "Boolean")
{
if ((Settings.Compatibility & Settings.Legacy.ConstIntEnums) != Settings.Legacy.None)
{
QualifiedType = "int";
}
else
{
//if (aux)
// CurrentType = EnumProcessor.TranslateEnumName(CurrentType);
#warning "Unecessary code"
if (normal)
QualifiedType = CurrentType.Insert(0, String.Format("{0}.", Settings.EnumsOutput));
else if (aux)
QualifiedType = CurrentType.Insert(0, String.Format("{0}.", Settings.EnumsAuxOutput));
}
}
else if (GLTypes.TryGetValue(CurrentType, out s))
@ -392,7 +394,7 @@ namespace Bind.Structures
else
{
// Better match: enum.Name == function.Category (e.g. GL_VERSION_1_1 etc)
if (Enum.GLEnums.ContainsKey(category))
if (enums.ContainsKey(category))
{
QualifiedType = String.Format("{0}.{1}", Settings.EnumsOutput, EnumProcessor.TranslateEnumName(category));
}
@ -410,30 +412,7 @@ namespace Bind.Structures
case "string": QualifiedType = "String"; break;
}
#warning "Stale code"
// This is not enum, default translation:
if (CurrentType == "PIXELFORMATDESCRIPTOR" || CurrentType == "LAYERPLANEDESCRIPTOR" ||
CurrentType == "GLYPHMETRICSFLOAT")
{
if (Settings.Compatibility == Settings.Legacy.Tao)
CurrentType = CurrentType.Insert(0, "Gdi.");
else
{
if (CurrentType == "PIXELFORMATDESCRIPTOR")
CurrentType = "PixelFormatDescriptor";
else if (CurrentType == "LAYERPLANEDESCRIPTOR")
CurrentType = "LayerPlaneDescriptor";
else if (CurrentType == "GLYPHMETRICSFLOAT")
CurrentType = "GlyphMetricsFloat";
}
}
else if (CurrentType == "XVisualInfo")
{
//p.Pointer = false;
//p.Reference = true;
}
else
QualifiedType = s;
QualifiedType = s;
}
}
@ -471,7 +450,7 @@ namespace Bind.Structures
// guarantee a stable order between program executions.
int result = this.CurrentType.CompareTo(other.CurrentType);
if (result == 0)
result = Pointer.CompareTo(other.Pointer);
result = Pointer.CompareTo(other.Pointer); // Must come after array/ref, see issue [#1098]
if (result == 0)
result = Reference.CompareTo(other.Reference);
if (result == 0)

View file

@ -4,6 +4,7 @@
*/
#endregion
using System;
using System.Diagnostics;
using Bind.Structures;
@ -47,19 +48,20 @@ namespace Bind.Wgl
public override void Process()
{
Type.Initialize(glTypemap, csTypemap);
Enum.Initialize(enumSpec, enumSpecExt);
Function.Initialize();
Delegate.Initialize(glSpec, glSpecExt);
throw new NotSupportedException();
//Type.Initialize(glTypemap, csTypemap);
//Enum.Initialize(enumSpec, enumSpecExt);
//Function.Initialize();
//Delegate.Initialize(glSpec, glSpecExt);
// Process enums and delegates - create wrappers.
Trace.WriteLine("Processing specs, please wait...");
//this.Translate();
//// Process enums and delegates - create wrappers.
//Trace.WriteLine("Processing specs, please wait...");
////this.Translate();
WriteBindings(
Delegate.Delegates,
Function.Wrappers,
Enum.GLEnums);
//WriteBindings(
// Delegate.Delegates,
// Function.Wrappers,
// Enum.GLEnums);
}
}
}