937 lines
39 KiB
C#
937 lines
39 KiB
C#
#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
|
|
}
|
|
}
|