Opentk/Source/OpenGL/Bind/TranslateSpecs.cs

497 lines
17 KiB
C#
Raw Normal View History

2006-10-08 18:26:43 +00:00
#region License
//Copyright (c) 2006 Stephen Apostolopoulos
//See license.txt for license info
#endregion
2006-09-28 22:07:53 +00:00
using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;
namespace OpenTK.OpenGL.Bind
{
2006-10-08 18:26:43 +00:00
#region WrapperTypes enum
2006-09-30 18:24:41 +00:00
public enum WrapperTypes
{
None,
VoidArray,
Array,
UncheckedParameter,
2006-09-30 18:24:41 +00:00
ReturnsString,
ReturnsVoidPointer,
}
2006-10-08 18:26:43 +00:00
#endregion
2006-09-30 18:24:41 +00:00
2006-09-28 22:07:53 +00:00
static class Translation
{
public static char[] Separators = { ' ', '\n', ',', '(', ')', ';', '#' };
#region Dictionaries
static Dictionary<string, string> parameter_names = new Dictionary<string, string>();
2006-10-10 23:40:36 +00:00
#region GL types dictionary
2006-09-28 22:07:53 +00:00
private static Dictionary<string, string> _gl_types;
2006-10-10 23:40:36 +00:00
public static Dictionary<string, string> GLTypes
2006-09-28 22:07:53 +00:00
{
get { return Translation._gl_types; }
set { Translation._gl_types = value; }
}
2006-10-10 23:40:36 +00:00
#endregion
#region CS types dictionary
2006-09-28 22:07:53 +00:00
private static Dictionary<string, string> _cs_types;
2006-10-10 23:40:36 +00:00
public static Dictionary<string, string> CSTypes
2006-09-28 22:07:53 +00:00
{
get { return Translation._cs_types; }
set { Translation._cs_types = value; }
}
#endregion
2006-10-10 23:40:36 +00:00
#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
2006-09-28 22:07:53 +00:00
#region Constructor
static Translation()
{
// Names
parameter_names.Add("base", "@base");
parameter_names.Add("object", "@object");
parameter_names.Add("string", "@string");
parameter_names.Add("ref", "reference");
parameter_names.Add("params", "parameters");
parameter_names.Add("in", "@in");
2006-10-10 23:40:36 +00:00
parameter_names.Add("class", "@class");
2006-09-28 22:07:53 +00:00
}
#endregion
#region Translate enums
2006-09-28 22:07:53 +00:00
public static void TranslateEnums(System.Collections.Hashtable enums)
{
// Add missing enums.
{
Enum e = new Enum();
Constant c;
e.Name = "SGIX_icc_texture";
c = new Constant("RGB_ICC_SGIX", "0x8460"); e.ConstantCollection.Add(c.Name, c);
c = new Constant("RGBA_ICC_SGIX", "0x8461"); e.ConstantCollection.Add(c.Name, c);
c = new Constant("ALPHA_ICC_SGIX", "0x8462"); e.ConstantCollection.Add(c.Name, c);
c = new Constant("LUMINANCE_ICC_SGIX", "0x8463"); e.ConstantCollection.Add(c.Name, c);
c = new Constant("INTENSITY_ICC_SGIX", "0x8464"); e.ConstantCollection.Add(c.Name, c);
c = new Constant("LUMINANCE_ALPHA_ICC_SGIX", "0x8465"); e.ConstantCollection.Add(c.Name, c);
c = new Constant("R5_G6_B5_ICC_SGIX", "0x8466"); e.ConstantCollection.Add(c.Name, c);
c = new Constant("R5_G6_B5_A8_ICC_SGIX", "0x8467"); e.ConstantCollection.Add(c.Name, c);
c = new Constant("ALPHA16_ICC_SGIX", "0x8468"); e.ConstantCollection.Add(c.Name, c);
c = new Constant("LUMINANCE16_ICC_SGIX", "0x8469"); e.ConstantCollection.Add(c.Name, c);
c = new Constant("INTENSITY16_ICC_SGIX", "0x846A"); e.ConstantCollection.Add(c.Name, c);
c = new Constant("LUMINANCE16_ALPHA8_ICC_SGIX", "0x846B"); e.ConstantCollection.Add(c.Name, c);
enums.Add(e.Name, e);
}
// Translate enums.
foreach (Enum e in enums.Values)
2006-09-28 22:07:53 +00:00
{
if (Char.IsDigit(e.Name[0]))
e.Name = e.Name.Insert(0, "_");
if (e.Name == "Boolean")
continue;
foreach (Constant c in e.ConstantCollection.Values)
{
// Prepend an '_' if the first letter is a number (e.g. 4_BYTES -> _4_BYTES)
if (Char.IsDigit(c.Name[0]))
c.Name = c.Name.Insert(0, "_");
// Prepend an '_' to the aliased value, if it starts with a number (e.g. DataType.4_BYTES -> DataType._4_BYTES)
if (c.Value.Contains(".") && Char.IsDigit(c.Value[c.Value.IndexOf('.') + 1]))
c.Value = c.Value.Insert(c.Value.IndexOf('.') + 1, "_");
// There are cases when a value is not a number but an aliased constant, with no enum specified.
// In this case try searching all enums for the correct constant to alias (stupid opengl group).
if (!c.Value.Contains(".") && !c.Value.StartsWith("0x") && !Char.IsDigit(c.Value[0]))
{
if (c.Value.StartsWith("GL_"))
c.Value = c.Value.TrimStart('G', 'L', '_');
if (Char.IsDigit(c.Value[0]))
c.Value = c.Value.Insert(0, "_");
foreach (Enum search_enum in enums.Values)
foreach (Constant search_constant in search_enum.ConstantCollection.Values)
if (search_constant.Name == c.Value || search_constant.Name == c.Value.TrimStart('_'))
c.Value = c.Value.Insert(0, search_enum.Name + ".");
}
// Handle enum.spec bugs:
if (c.Value.Contains("LightProperty"))
c.Value = c.Value.Replace("LightProperty", "LightParameter");
}
2006-09-28 22:07:53 +00:00
}
2006-09-28 22:07:53 +00:00
}
2006-09-28 22:07:53 +00:00
#endregion
#region Translate functions
2006-09-28 22:07:53 +00:00
public static void TranslateFunctions(List<Function> functions, Hashtable enums, out List<Function> wrappers)
{
foreach (Function f in functions)
{
TranslateReturnValue(f, enums);
TranslateParameters(f, enums);
if (f.NeedsWrapper)
f.Name = f.Name + "_";
}
wrappers = GenerateWrappers(functions);
2006-09-28 22:07:53 +00:00
}
2006-09-30 18:24:41 +00:00
#region Translate return value
2006-09-28 22:07:53 +00:00
private static void TranslateReturnValue(Function f, Hashtable enums)
{
string s;
if (f.ReturnValue == "void")
return;
2006-10-10 23:40:36 +00:00
if (GLTypes.TryGetValue(f.ReturnValue, out s))
2006-09-28 22:07:53 +00:00
f.ReturnValue = s;
if (f.ReturnValue == "void[]")
{
2006-09-30 18:24:41 +00:00
f.NeedsWrapper = true;
f.WrapperType = WrapperTypes.ReturnsVoidPointer;
2006-09-28 22:07:53 +00:00
f.ReturnValue = "IntPtr";
}
2006-09-30 18:24:41 +00:00
if (f.ReturnValue == "GLstring")
2006-09-28 22:07:53 +00:00
{
f.NeedsWrapper = true;
2006-09-30 18:24:41 +00:00
f.WrapperType = WrapperTypes.ReturnsString;
f.ReturnValue = "IntPtr";
2006-09-28 22:07:53 +00:00
}
}
2006-09-30 18:24:41 +00:00
2006-09-28 22:07:53 +00:00
#endregion
2006-09-30 18:24:41 +00:00
#region Translate parameters
2006-09-28 22:07:53 +00:00
private static void TranslateParameters(Function f, Hashtable enums)
{
string s;
foreach (Parameter p in f.Parameters) // Translate each parameter of the function, and check for needed wrappers.
2006-09-28 22:07:53 +00:00
{
#region Translate parameter name
2006-09-28 22:07:53 +00:00
if (parameter_names.TryGetValue(p.Name, out s))
p.Name = s;
#endregion
#region Translate parameter type
//if (p.Type.Contains("Boolean"))
//{
// p.Type = "GLboolean";
//}
if (enums.ContainsKey(p.Type))
2006-09-28 22:07:53 +00:00
{
p.Type = "Enums." + p.Type;
}
else if (p.Type == "GLenum")
{
2006-10-08 18:26:43 +00:00
if (enums.ContainsKey(f.Category))
p.Type = "Enums." + f.Category;
}
2006-10-10 23:40:36 +00:00
else if (GLTypes.TryGetValue(p.Type, out s))
2006-09-28 22:07:53 +00:00
p.Type = s;
#endregion
#region Check for needed wrappers
if (p.Type.Contains("ushort") && f.Name.Contains("LineStipple")) // glLineStipple needs wrapper to allow for unchecked mask values.
2006-09-30 18:24:41 +00:00
{
p.NeedsWrapper = true;
p.WrapperType = WrapperTypes.UncheckedParameter;
p.Unchecked = true;
2006-09-30 18:24:41 +00:00
}
else if (p.Array && p.Type.Contains("string")) // string parameters do not need special wrappers.
2006-09-28 22:07:53 +00:00
{
p.NeedsWrapper = false;
p.WrapperType = WrapperTypes.None;
2006-09-28 22:07:53 +00:00
}
else if (p.Array && p.Type.Contains("char")) // GLchar[] parameters should become (in) string or (out) StringBuilder
{
if (p.Flow == Parameter.FlowDirection.Out)
p.Type = "StringBuilder";
else
p.Type = "string";
p.Array = false;
}
else if (p.Array) // All other array parameters need wrappers (around IntPtr).
2006-09-28 22:07:53 +00:00
{
p.NeedsWrapper = true;
if (p.Type.Contains("void"))
p.WrapperType = WrapperTypes.VoidArray;
else
p.WrapperType = WrapperTypes.Array;
2006-09-28 22:07:53 +00:00
p.Type = "IntPtr";
p.Array = false; // We do not want an array of IntPtrs (IntPtr[]) - it is the IntPtr that points to the array.
p.Flow = Parameter.FlowDirection.Undefined; // The same wrapper works for either in or out parameters.
2006-09-30 18:24:41 +00:00
}
if (p.NeedsWrapper) // If there is at least 1 parameter that needs wrappers, mark the funcction for wrapping.
2006-09-30 18:24:41 +00:00
{
2006-09-28 22:07:53 +00:00
f.NeedsWrapper = true;
f.WrapperType = p.WrapperType;
2006-09-28 22:07:53 +00:00
}
#endregion
2006-09-28 22:07:53 +00:00
}
}
2006-09-28 22:07:53 +00:00
#endregion
2006-09-30 18:24:41 +00:00
#region Generate wrappers
private static List<Function> GenerateWrappers(List<Function> functions)
2006-09-28 22:07:53 +00:00
{
List<Function> wrappers = new List<Function>();
Function w;
2006-09-28 22:07:53 +00:00
foreach (Function f in functions)
2006-09-28 22:07:53 +00:00
{
if (f.NeedsWrapper)
{
if (f.WrapperType == WrapperTypes.UncheckedParameter)
{
w = new Function(f);
w.Name = w.Name.TrimEnd('_');
// Search and replace ushort parameters with ints.
Predicate<Parameter> is_ushort_parameter = new Predicate<Parameter>(delegate(Parameter p) { return p.Type == "GLushort"; });
Parameter oldp = w.Parameters.Find(is_ushort_parameter);
Parameter newp = new Parameter(oldp);
newp.Type = "GLint";
w.Parameters = w.Parameters.ReplaceAll(oldp, newp);
// Call the low-level function wrapping (all parameters marked with Unchecked will automatically
// be decorated with the unchecked keyword).
w.Body.Add((f.ReturnValue.Contains("void") ? "" : "return ") + f.CallString() + ";");
// Add the wrapper.
wrappers.Add(w);
continue;
}
if (f.WrapperType == WrapperTypes.ReturnsString)
{
w = new Function(f);
w.Name = w.Name.TrimEnd('_');
// Replace the IntPtr return value with string.
w.ReturnValue = "string";
// Wrap the call to the low-level function (marshal the IntPtr to string).
w.Body.Add("return Marshal.PtrToStringAnsi(" + f.CallString() + ");");
// Add the wrapper.
wrappers.Add(w);
continue;
}
//if (
WrapPointers(f, wrappers);
count = 0;
}
2006-09-28 22:07:53 +00:00
}
return wrappers;
2006-09-28 22:07:53 +00:00
}
static int count = 0;
private static void WrapPointers(Function f, List<Function> wrappers)
2006-09-28 22:07:53 +00:00
{
if (count == 0)
2006-09-28 22:07:53 +00:00
{
wrappers.Add(IntPtrToIntPtr(f));
}
2006-09-28 22:07:53 +00:00
if (count >= 0 && count < f.Parameters.Count)
{
if (f.Parameters[count].NeedsWrapper)
2006-09-28 22:07:53 +00:00
{
++count;
WrapPointers(f, wrappers);
--count;
Function w = IntPtrToObject(f, count);
wrappers.Add(w);
++count;
WrapPointers(w, wrappers);
--count;
if (f.Parameters[count].WrapperType == WrapperTypes.Array)
{
w = IntPtrToArray(f, count);
wrappers.Add(w);
++count;
WrapPointers(w, wrappers);
--count;
}
}
else
{
++count;
WrapPointers(f, wrappers);
--count;
}
}
}
2006-09-28 22:07:53 +00:00
// IntPtr -> IntPtr wrapper.
private static Function IntPtrToIntPtr(Function f)
{
Function w = new Function(f);
w.Name = w.Name.TrimEnd('_');
w.Body.Add((f.ReturnValue.Contains("void") ? "" : "return ") + f.CallString() + ";");
return w;
}
// IntPtr -> object wrapper.
private static Function IntPtrToObject(Function f, int index)
{
Function w = new Function(f);
w.Name = w.Name.TrimEnd('_');
Parameter newp = new Parameter(f.Parameters[index]);
newp.Type = "object";
if (newp.Flow == Parameter.FlowDirection.Out)
newp.Flow = Parameter.FlowDirection.Undefined;
w.Parameters = w.Parameters.Replace(f.Parameters[index], newp);
// In the function body we should pin all objects in memory before calling the
// low-level function.
w.Body = GenerateBodyForPins(w);
return w;
}
// IntPtr -> GL[...] wrapper.
private static Function IntPtrToArray(Function f, int index)
{
Function w = new Function(f);
w.Name = w.Name.TrimEnd('_');
// Search and replace IntPtr parameters with the know parameter types:
Parameter newp = new Parameter(f.Parameters[index]);
newp.Type = f.Parameters[index].PreviousType;
newp.Array = true;
w.Parameters = w.Parameters.Replace(f.Parameters[index], newp);
// In the function body we should pin all objects in memory before calling the
// low-level function.
w.Body = GenerateBodyForPins(w);
return w;
}
private static FunctionBody GenerateBodyForPins(Function w)
{
FunctionBody body = new FunctionBody();
int i = 0;
StringBuilder sb = new StringBuilder();
sb.Append("(");
foreach (Parameter p in w.Parameters)
{
if (p.Type == "object" || p.Array && !p.Type.Contains("string")) // we should allow the default marshalling behavior for strings.
{
body.Add("GCHandle h" + i + " = GCHandle.Alloc(" + p.Name + ", GCHandleType.Pinned);");
sb.Append("h" + i + ".AddrOfPinnedObject()" + ", ");
i++;
2006-09-28 22:07:53 +00:00
}
else
{
sb.Append(p.Name + ", ");
}
}
sb.Replace(", ", ")", sb.Length - 2, 2);
body.Add("try");
body.Add("{");
body.Add(
" " +
(w.ReturnValue.Contains("void") ? "" : "return ") +
w.Name + "_" +
sb.ToString() +
";");
body.Add("}");
body.Add("finally");
body.Add("{");
while (i > 0)
{
body.Add(" h" + --i + ".Free();");
2006-09-28 22:07:53 +00:00
}
body.Add("}");
return body;
2006-09-28 22:07:53 +00:00
}
#endregion
2006-09-28 22:07:53 +00:00
#endregion
}
}