Preparing code generator for ImPlot, ImNodes and ImGuizmo code generation

internals
Alex Hildebrand 4 years ago
parent 9b74ee4f79
commit 02a838f88f
  1. 19
      src/CodeGenerator/CodeGenerator.csproj
  2. 7
      src/CodeGenerator/ImguiDefinitions.cs
  3. 94
      src/CodeGenerator/Program.cs
  4. 34
      src/CodeGenerator/TypeInfo.cs
  5. 0
      src/CodeGenerator/definitions/cimgui/definitions.json
  6. 0
      src/CodeGenerator/definitions/cimgui/structs_and_enums.json
  7. 0
      src/CodeGenerator/definitions/cimgui/variants.json

@ -6,13 +6,24 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Content Include="structs_and_enums.json" CopyToOutputDirectory="PreserveNewest" /> <Content Include="definitions\cimgui\structs_and_enums.json" CopyToOutputDirectory="PreserveNewest" />
<Content Include="definitions.json" CopyToOutputDirectory="PreserveNewest" /> <Content Include="definitions\cimgui\definitions.json" CopyToOutputDirectory="PreserveNewest" />
<Content Include="variants.json" CopyToOutputDirectory="PreserveNewest" /> <Content Include="definitions\cimgui\variants.json" CopyToOutputDirectory="PreserveNewest" />
<Content Include="definitions\cimplot\structs_and_enums.json" CopyToOutputDirectory="PreserveNewest" />
<Content Include="definitions\cimplot\definitions.json" CopyToOutputDirectory="PreserveNewest" />
<Content Include="definitions\cimplot\variants.json" CopyToOutputDirectory="PreserveNewest" />
<Content Include="definitions\cimnodes\structs_and_enums.json" CopyToOutputDirectory="PreserveNewest" />
<Content Include="definitions\cimnodes\definitions.json" CopyToOutputDirectory="PreserveNewest" />
<Content Include="definitions\cimnodes\variants.json" CopyToOutputDirectory="PreserveNewest" />
<Content Include="definitions\cimguizmo\structs_and_enums.json" CopyToOutputDirectory="PreserveNewest" />
<Content Include="definitions\cimguizmo\definitions.json" CopyToOutputDirectory="PreserveNewest" />
<Content Include="definitions\cimguizmo\variants.json" CopyToOutputDirectory="PreserveNewest" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" /> <PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
</ItemGroup> </ItemGroup>
</Project> </Project>

@ -41,7 +41,7 @@ namespace CodeGenerator
JObject variantsJson = null; JObject variantsJson = null;
if (File.Exists(Path.Combine(directory, "variants.json"))) if (File.Exists(Path.Combine(directory, "variants.json")))
{ {
using (StreamReader fs = File.OpenText(Path.Combine(AppContext.BaseDirectory, "variants.json"))) using (StreamReader fs = File.OpenText(Path.Combine(directory, "variants.json")))
using (JsonTextReader jr = new JsonTextReader(fs)) using (JsonTextReader jr = new JsonTextReader(fs))
{ {
variantsJson = JObject.Load(jr); variantsJson = JObject.Load(jr);
@ -275,6 +275,9 @@ namespace CodeGenerator
ret = ret.Substring(0, ret.Length - 1); ret = ret.Substring(0, ret.Length - 1);
} }
if (Char.IsDigit(ret.First()))
ret = "_" + ret;
return ret; return ret;
} }
} }
@ -368,7 +371,7 @@ namespace CodeGenerator
TypeVariants = typeVariants; TypeVariants = typeVariants;
IsEnum = enums.Any(t => t.Name == type || t.FriendlyName == type); IsEnum = enums.Any(t => t.Name == type || t.FriendlyName == type || TypeInfo.WellKnownEnums.Contains(type));
} }
private int ParseSizeString(string sizePart, EnumDefinition[] enums) private int ParseSizeString(string sizePart, EnumDefinition[] enums)

@ -25,8 +25,46 @@ namespace CodeGenerator
outputPath = AppContext.BaseDirectory; outputPath = AppContext.BaseDirectory;
} }
string libraryName;
if (args.Length > 1)
{
libraryName = args[1];
}
else
{
libraryName = "cimgui";
}
string projectNamespace = libraryName switch
{
"cimgui" => "ImGuiNET",
"cimplot" => "ImGuiNET",
"cimnodes" => "ImGuiNET",
"cimguizmo" => "ImGuiNET",
_ => throw new NotImplementedException()
};
string classPrefix = libraryName switch
{
"cimgui" => "ImGui",
"cimplot" => "ImPlot",
"cimnodes" => "ImNodes",
"cimguizmo" => "ImGuizmo",
_ => throw new NotImplementedException()
};
string dllName = libraryName switch
{
"cimgui" => "cimgui",
"cimplot" => "cimgui",
"cimnodes" => "cimgui",
"cimguizmo" => "cimgui",
_ => throw new NotImplementedException()
};
string definitionsPath = Path.Combine(AppContext.BaseDirectory, "definitions", libraryName);
var defs = new ImguiDefinitions(); var defs = new ImguiDefinitions();
defs.LoadFrom(AppContext.BaseDirectory); defs.LoadFrom(definitionsPath);
Console.WriteLine($"Outputting generated code files to {outputPath}."); Console.WriteLine($"Outputting generated code files to {outputPath}.");
@ -34,7 +72,7 @@ namespace CodeGenerator
{ {
using (CSharpCodeWriter writer = new CSharpCodeWriter(Path.Combine(outputPath, ed.FriendlyName + ".gen.cs"))) using (CSharpCodeWriter writer = new CSharpCodeWriter(Path.Combine(outputPath, ed.FriendlyName + ".gen.cs")))
{ {
writer.PushBlock("namespace ImGuiNET"); writer.PushBlock($"namespace {projectNamespace}");
if (ed.FriendlyName.Contains("Flags")) if (ed.FriendlyName.Contains("Flags"))
{ {
writer.WriteLine("[System.Flags]"); writer.WriteLine("[System.Flags]");
@ -62,7 +100,7 @@ namespace CodeGenerator
writer.Using("System.Runtime.CompilerServices"); writer.Using("System.Runtime.CompilerServices");
writer.Using("System.Text"); writer.Using("System.Text");
writer.WriteLine(string.Empty); writer.WriteLine(string.Empty);
writer.PushBlock("namespace ImGuiNET"); writer.PushBlock($"namespace {projectNamespace}");
writer.PushBlock($"public unsafe partial struct {td.Name}"); writer.PushBlock($"public unsafe partial struct {td.Name}");
foreach (TypeReference field in td.Fields) foreach (TypeReference field in td.Fields)
@ -209,7 +247,7 @@ namespace CodeGenerator
{ {
defaults.Add(orderedDefaults[j].Key, orderedDefaults[j].Value); defaults.Add(orderedDefaults[j].Key, orderedDefaults[j].Value);
} }
EmitOverload(writer, overload, defaults, "NativePtr"); EmitOverload(writer, overload, defaults, "NativePtr", classPrefix);
} }
} }
} }
@ -219,14 +257,14 @@ namespace CodeGenerator
} }
} }
using (CSharpCodeWriter writer = new CSharpCodeWriter(Path.Combine(outputPath, "ImGuiNative.gen.cs"))) using (CSharpCodeWriter writer = new CSharpCodeWriter(Path.Combine(outputPath, $"{classPrefix}Native.gen.cs")))
{ {
writer.Using("System"); writer.Using("System");
writer.Using("System.Numerics"); writer.Using("System.Numerics");
writer.Using("System.Runtime.InteropServices"); writer.Using("System.Runtime.InteropServices");
writer.WriteLine(string.Empty); writer.WriteLine(string.Empty);
writer.PushBlock("namespace ImGuiNET"); writer.PushBlock($"namespace {projectNamespace}");
writer.PushBlock("public static unsafe partial class ImGuiNative"); writer.PushBlock($"public static unsafe partial class {classPrefix}Native");
foreach (FunctionDefinition fd in defs.Functions) foreach (FunctionDefinition fd in defs.Functions)
{ {
foreach (OverloadDefinition overload in fd.Overloads) foreach (OverloadDefinition overload in fd.Overloads)
@ -273,12 +311,12 @@ namespace CodeGenerator
if (isUdtVariant) if (isUdtVariant)
{ {
writer.WriteLine($"[DllImport(\"cimgui\", CallingConvention = CallingConvention.Cdecl, EntryPoint = \"{exportedName}\")]"); writer.WriteLine($"[DllImport(\"{dllName}\", CallingConvention = CallingConvention.Cdecl, EntryPoint = \"{exportedName}\")]");
} }
else else
{ {
writer.WriteLine("[DllImport(\"cimgui\", CallingConvention = CallingConvention.Cdecl)]"); writer.WriteLine($"[DllImport(\"{dllName}\", CallingConvention = CallingConvention.Cdecl)]");
} }
writer.WriteLine($"public static extern {ret} {methodName}({parameters});"); writer.WriteLine($"public static extern {ret} {methodName}({parameters});");
} }
@ -287,15 +325,15 @@ namespace CodeGenerator
writer.PopBlock(); writer.PopBlock();
} }
using (CSharpCodeWriter writer = new CSharpCodeWriter(Path.Combine(outputPath, "ImGui.gen.cs"))) using (CSharpCodeWriter writer = new CSharpCodeWriter(Path.Combine(outputPath, $"{classPrefix}.gen.cs")))
{ {
writer.Using("System"); writer.Using("System");
writer.Using("System.Numerics"); writer.Using("System.Numerics");
writer.Using("System.Runtime.InteropServices"); writer.Using("System.Runtime.InteropServices");
writer.Using("System.Text"); writer.Using("System.Text");
writer.WriteLine(string.Empty); writer.WriteLine(string.Empty);
writer.PushBlock("namespace ImGuiNET"); writer.PushBlock($"namespace {projectNamespace}");
writer.PushBlock("public static unsafe partial class ImGui"); writer.PushBlock($"public static unsafe partial class {classPrefix}");
foreach (FunctionDefinition fd in defs.Functions) foreach (FunctionDefinition fd in defs.Functions)
{ {
if (TypeInfo.SkippedFunctions.Contains(fd.Name)) { continue; } if (TypeInfo.SkippedFunctions.Contains(fd.Name)) { continue; }
@ -336,7 +374,7 @@ namespace CodeGenerator
{ {
defaults.Add(orderedDefaults[j].Key, orderedDefaults[j].Value); defaults.Add(orderedDefaults[j].Key, orderedDefaults[j].Value);
} }
EmitOverload(writer, overload, defaults, null); EmitOverload(writer, overload, defaults, null, classPrefix);
} }
} }
} }
@ -381,7 +419,8 @@ namespace CodeGenerator
CSharpCodeWriter writer, CSharpCodeWriter writer,
OverloadDefinition overload, OverloadDefinition overload,
Dictionary<string, string> defaultValues, Dictionary<string, string> defaultValues,
string selfName) string selfName,
string classPrefix)
{ {
if (overload.Parameters.Where(tr => tr.Name.EndsWith("_begin") || tr.Name.EndsWith("_end")) if (overload.Parameters.Where(tr => tr.Name.EndsWith("_begin") || tr.Name.EndsWith("_end"))
.Any(tr => !defaultValues.ContainsKey(tr.Name))) .Any(tr => !defaultValues.ContainsKey(tr.Name)))
@ -481,6 +520,15 @@ namespace CodeGenerator
postCallLines.Add($"}}"); postCallLines.Add($"}}");
} }
} }
else if (defaultValues.TryGetValue(tr.Name, out string defaultVal))
{
if (!CorrectDefaultValue(defaultVal, tr, out string correctedDefault))
{
correctedDefault = defaultVal;
}
marshalledParameters[i] = new MarshalledParameter(nativeTypeName, false, correctedIdentifier, true);
preCallLines.Add($"{nativeTypeName} {correctedIdentifier} = {correctedDefault};");
}
else if (tr.Type == "char* []") else if (tr.Type == "char* []")
{ {
string nativeArgName = "native_" + tr.Name; string nativeArgName = "native_" + tr.Name;
@ -518,15 +566,6 @@ namespace CodeGenerator
preCallLines.Add($" offset += {correctedIdentifier}_byteCounts[i] + 1;"); preCallLines.Add($" offset += {correctedIdentifier}_byteCounts[i] + 1;");
preCallLines.Add("}"); preCallLines.Add("}");
} }
else if (defaultValues.TryGetValue(tr.Name, out string defaultVal))
{
if (!CorrectDefaultValue(defaultVal, tr, out string correctedDefault))
{
correctedDefault = defaultVal;
}
marshalledParameters[i] = new MarshalledParameter(nativeTypeName, false, correctedIdentifier, true);
preCallLines.Add($"{nativeTypeName} {correctedIdentifier} = {correctedDefault};");
}
else if (tr.Type == "bool") else if (tr.Type == "bool")
{ {
string nativeArgName = "native_" + tr.Name; string nativeArgName = "native_" + tr.Name;
@ -557,7 +596,7 @@ namespace CodeGenerator
marshalledParameters[i] = new MarshalledParameter(wrappedParamType, false, nativeArgName, false); marshalledParameters[i] = new MarshalledParameter(wrappedParamType, false, nativeArgName, false);
preCallLines.Add($"{tr.Type} {nativeArgName} = {correctedIdentifier}.NativePtr;"); preCallLines.Add($"{tr.Type} {nativeArgName} = {correctedIdentifier}.NativePtr;");
} }
else if ((tr.Type.EndsWith("*") || tr.Type.Contains("[") || tr.Type.EndsWith("&")) && tr.Type != "void*" && tr.Type != "ImGuiContext*") else if ((tr.Type.EndsWith("*") || tr.Type.Contains("[") || tr.Type.EndsWith("&")) && tr.Type != "void*" && tr.Type != "ImGuiContext*" && tr.Type != "ImPlotContext*"&& tr.Type != "EditorContext*")
{ {
string nonPtrType; string nonPtrType;
if (tr.Type.Contains("[")) if (tr.Type.Contains("["))
@ -634,7 +673,7 @@ namespace CodeGenerator
targetName = targetName.Substring(0, targetName.IndexOf("_nonUDT")); targetName = targetName.Substring(0, targetName.IndexOf("_nonUDT"));
} }
writer.WriteLine($"{ret}ImGuiNative.{targetName}({nativeInvocationStr});"); writer.WriteLine($"{ret}{classPrefix}Native.{targetName}({nativeInvocationStr});");
foreach (string line in postCallLines) foreach (string line in postCallLines)
{ {
@ -736,7 +775,7 @@ namespace CodeGenerator
private static bool CorrectDefaultValue(string defaultVal, TypeReference tr, out string correctedDefault) private static bool CorrectDefaultValue(string defaultVal, TypeReference tr, out string correctedDefault)
{ {
if (tr.Type == "ImGuiContext*") if (tr.Type == "ImGuiContext*" || tr.Type == "ImPlotContext*" || tr.Type == "EditorContext*")
{ {
correctedDefault = "IntPtr.Zero"; correctedDefault = "IntPtr.Zero";
return true; return true;
@ -754,6 +793,9 @@ namespace CodeGenerator
if (tr.IsEnum) if (tr.IsEnum)
{ {
if (defaultVal.StartsWith("-"))
correctedDefault = $"({tr.Type})({defaultVal})";
else
correctedDefault = $"({tr.Type}){defaultVal}"; correctedDefault = $"({tr.Type}){defaultVal}";
return true; return true;
} }

@ -14,7 +14,12 @@ namespace CodeGenerator
{ "ImFileHandle", "IntPtr" }, { "ImFileHandle", "IntPtr" },
{ "ImU8", "byte" }, { "ImU8", "byte" },
{ "ImS8", "sbyte" }, { "ImS8", "sbyte" },
{ "ImU16", "ushort" },
{ "ImS16", "short" },
{ "ImU32", "uint" },
{ "ImS32", "int" },
{ "ImU64", "ulong" }, { "ImU64", "ulong" },
{ "ImS64", "long" },
{ "unsigned short", "ushort" }, { "unsigned short", "ushort" },
{ "unsigned int", "uint" }, { "unsigned int", "uint" },
{ "ImVec2", "Vector2" }, { "ImVec2", "Vector2" },
@ -29,10 +34,11 @@ namespace CodeGenerator
{ "ImDrawIdx", "ushort" }, { "ImDrawIdx", "ushort" },
{ "ImDrawListSharedData", "IntPtr" }, { "ImDrawListSharedData", "IntPtr" },
{ "ImDrawListSharedData*", "IntPtr" }, { "ImDrawListSharedData*", "IntPtr" },
{ "ImU32", "uint" },
{ "ImDrawCallback", "IntPtr" }, { "ImDrawCallback", "IntPtr" },
{ "size_t", "uint" }, { "size_t", "uint" },
{ "ImGuiContext*", "IntPtr" }, { "ImGuiContext*", "IntPtr" },
{ "ImPlotContext*", "IntPtr" },
{ "EditorContext*", "IntPtr" },
{ "float[2]", "Vector2*" }, { "float[2]", "Vector2*" },
{ "float[3]", "Vector3*" }, { "float[3]", "Vector3*" },
{ "float[4]", "Vector4*" }, { "float[4]", "Vector4*" },
@ -45,6 +51,11 @@ namespace CodeGenerator
{ "unsigned char[256]", "byte*"}, { "unsigned char[256]", "byte*"},
}; };
public static readonly List<string> WellKnownEnums = new List<string>()
{
"ImGuiMouseButton"
};
public static readonly Dictionary<string, string> WellKnownFieldReplacements = new Dictionary<string, string>() public static readonly Dictionary<string, string> WellKnownFieldReplacements = new Dictionary<string, string>()
{ {
{ "bool", "bool" }, // Force bool to remain as bool in type-safe wrappers. { "bool", "bool" }, // Force bool to remain as bool in type-safe wrappers.
@ -62,6 +73,8 @@ namespace CodeGenerator
{ {
{ "((void *)0)", "null" }, { "((void *)0)", "null" },
{ "((void*)0)", "null" }, { "((void*)0)", "null" },
{ "NULL", "null"},
{ "nullptr", "null"},
{ "ImVec2(0,0)", "new Vector2()" }, { "ImVec2(0,0)", "new Vector2()" },
{ "ImVec2(-1,0)", "new Vector2(-1, 0)" }, { "ImVec2(-1,0)", "new Vector2(-1, 0)" },
{ "ImVec2(1,0)", "new Vector2(1, 0)" }, { "ImVec2(1,0)", "new Vector2(1, 0)" },
@ -69,9 +82,26 @@ namespace CodeGenerator
{ "ImVec2(0,1)", "new Vector2(0, 1)" }, { "ImVec2(0,1)", "new Vector2(0, 1)" },
{ "ImVec4(0,0,0,0)", "new Vector4()" }, { "ImVec4(0,0,0,0)", "new Vector4()" },
{ "ImVec4(1,1,1,1)", "new Vector4(1, 1, 1, 1)" }, { "ImVec4(1,1,1,1)", "new Vector4(1, 1, 1, 1)" },
{ "ImVec4(0,0,0,-1)", "new Vector4(0, 0, 0, -1)" },
{ "ImPlotPoint(0,0)", "new ImPlotPoint { x = 0, y = 0 }" },
{ "ImPlotPoint(1,1)", "new ImPlotPoint { x = 1, y = 1 }" },
{ "ImDrawCornerFlags_All", "ImDrawCornerFlags.All" }, { "ImDrawCornerFlags_All", "ImDrawCornerFlags.All" },
{ "ImPlotFlags_None", "ImPlotFlags.None"},
{ "ImPlotAxisFlags_None", "ImPlotAxisFlags.None"},
{ "ImPlotAxisFlags_NoGridLines", "ImPlotAxisFlags.NoGridLines"},
{ "ImGuiCond_Once", "ImGuiCond.Once"},
{ "ImPlotOrientation_Vertical", "ImPlotOrientation.Vertical"},
{ "PinShape_CircleFilled", "PinShape._CircleFilled"},
{ "FLT_MAX", "float.MaxValue" }, { "FLT_MAX", "float.MaxValue" },
{ "(((ImU32)(255)<<24)|((ImU32)(255)<<16)|((ImU32)(255)<<8)|((ImU32)(255)<<0))", "0xFFFFFFFF" } { "(((ImU32)(255)<<24)|((ImU32)(255)<<16)|((ImU32)(255)<<8)|((ImU32)(255)<<0))", "0xFFFFFFFF" },
{ "sizeof(ImU8)", "sizeof(byte)"},
{ "sizeof(ImS8)", "sizeof(sbyte)"},
{ "sizeof(ImU16)", "sizeof(ushort)"},
{ "sizeof(ImS16)", "sizeof(short)"},
{ "sizeof(ImU32)", "sizeof(uint)"},
{ "sizeof(ImS32)", "sizeof(int)"},
{ "sizeof(ImU64)", "sizeof(ulong)"},
{ "sizeof(ImS64)", "sizeof(long)"}
}; };
public static readonly Dictionary<string, string> IdentifierReplacements = new Dictionary<string, string>() public static readonly Dictionary<string, string> IdentifierReplacements = new Dictionary<string, string>()

Loading…
Cancel
Save