Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for Bitfields #245

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 62 additions & 5 deletions src/CodeGenerator/ImguiDefinitions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,14 @@ static int GetInt(JToken token, string key)
if (v == null) return 0;
return v.ToObject<int>();
}

static int? GetOptionalInt(JToken token, string key)
{
var v = token[key];
if (v == null) return null;
return v.ToObject<int>();
}

public void LoadFrom(string directory)
{

Expand Down Expand Up @@ -93,7 +101,9 @@ public void LoadFrom(string directory)
v["type"].ToString(),
GetInt(v, "size"),
v["template_type"]?.ToString(),
Enums);
Enums,
typeVariants: null,
GetOptionalInt(v, "bitfield"));
}).Where(tr => tr != null).ToArray();
return new TypeDefinition(name, fields);
}).Where(x => x != null).ToArray();
Expand Down Expand Up @@ -336,12 +346,34 @@ class TypeDefinition
{
public string Name { get; }
public TypeReference[] Fields { get; }
public BitField[] BitFields { get; }

public TypeDefinition(string name, TypeReference[] fields)
{
Name = name;
Fields = fields;

var bitFields = new List<BitField>();
int bitFieldStartI = -1;
for (int i = 0; i < fields.Length; i++)
{
if (fields[i].BitSize.HasValue && bitFieldStartI < 0)
bitFieldStartI = i;

if (!fields[i].BitSize.HasValue && bitFieldStartI >= 0)
{
bitFields.Add(new BitField(bitFields.Count, fields[bitFieldStartI..i]));
bitFieldStartI = -1;
}
}
if (bitFieldStartI >= 0)
bitFields.Add(new BitField(bitFields.Count, fields[bitFieldStartI..]));
BitFields = bitFields.ToArray();
}

public BitField GetBitFieldContaining(TypeReference field) =>
BitFields.FirstOrDefault(bitField => bitField.Fields.Contains(field))
?? throw new ArgumentException("Given is not part of any bit field");
}

class TypeReference
Expand All @@ -353,17 +385,18 @@ class TypeReference
public bool IsFunctionPointer { get; }
public string[] TypeVariants { get; }
public bool IsEnum { get; }
public int? BitSize { get; }

public TypeReference(string name, string type, int asize, EnumDefinition[] enums)
: this(name, type, asize, null, enums, null) { }
: this(name, type, asize, null, enums, null, null) { }

public TypeReference(string name, string type, int asize, EnumDefinition[] enums, string[] typeVariants)
: this(name, type, asize, null, enums, typeVariants) { }
: this(name, type, asize, null, enums, typeVariants, null) { }

public TypeReference(string name, string type, int asize, string templateType, EnumDefinition[] enums)
: this(name, type, asize, templateType, enums, null) { }
: this(name, type, asize, templateType, enums, null, null) { }

public TypeReference(string name, string type, int asize, string templateType, EnumDefinition[] enums, string[] typeVariants)
public TypeReference(string name, string type, int asize, string templateType, EnumDefinition[] enums, string[] typeVariants, int? bitSize)
{
Name = name;
Type = type.Replace("const", string.Empty).Trim();
Expand Down Expand Up @@ -410,6 +443,8 @@ public TypeReference(string name, string type, int asize, string templateType, E
TypeVariants = typeVariants;

IsEnum = enums.Any(t => t.Names.Contains(type) || t.FriendlyNames.Contains(type) || TypeInfo.WellKnownEnums.Contains(type));

BitSize = bitSize;
}

private int ParseSizeString(string sizePart, EnumDefinition[] enums)
Expand Down Expand Up @@ -453,6 +488,28 @@ public TypeReference WithVariant(int variantIndex, EnumDefinition[] enums)
}
}

class BitField
{
public string Name { get; }
public string Type { get; }
public TypeReference[] Fields { get; }

public BitField(int index, IEnumerable<TypeReference> fields)
{
Name = $"_bitField_{index}";
Fields = fields.ToArray();
Type = TypeInfo.GetTypeForBitfield(fields.Sum(f => f.BitSize.Value));
}

public int OffsetOf(TypeReference field)
{
var fieldIndex = Array.IndexOf(Fields, field);
if (fieldIndex < 0)
throw new ArgumentException("Given field is not part of the bit field");
return Fields.Take(fieldIndex).Sum(f => f.BitSize.Value);
}
}

class FunctionDefinition
{
public string Name { get; }
Expand Down
19 changes: 19 additions & 0 deletions src/CodeGenerator/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,14 @@ static void Main(string[] args)
}
}
}
else if (field.BitSize.HasValue)
{
var bitField = td.GetBitFieldContaining(field);
if (bitField.OffsetOf(field) > 0)
continue;

writer.WriteLine($"public {bitField.Type} {bitField.Name};");
}
else
{
writer.WriteLine($"public {typeStr} {field.Name};");
Expand Down Expand Up @@ -170,6 +178,17 @@ static void Main(string[] args)
string addrTarget = TypeInfo.LegalFixedTypes.Contains(rawType) ? $"NativePtr->{field.Name}" : $"&NativePtr->{field.Name}_0";
writer.WriteLine($"public RangeAccessor<{typeStr}> {field.Name} => new RangeAccessor<{typeStr}>({addrTarget}, {field.ArraySize});");
}
else if (field.BitSize.HasValue)
{
var bitField = td.GetBitFieldContaining(field);
var offset = bitField.OffsetOf(field);
var mask = (ulong)(1 << field.BitSize) - 1 << offset;

writer.PushBlock($"public {typeStr} {field.Name}");
writer.WriteLine($"get => ({typeStr})Util.GetBits(NativePtr->{bitField.Name}, {offset}, {field.BitSize});");
writer.WriteLine($"set => NativePtr->{bitField.Name} = Util.SetBits(NativePtr->{bitField.Name}, {offset}, {field.BitSize}, ({bitField.Type})value);");
writer.PopBlock();
}
else if (typeStr.Contains("ImVector"))
{
string vectorElementType = GetTypeString(field.TemplateType, false);
Expand Down
9 changes: 9 additions & 0 deletions src/CodeGenerator/TypeInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -160,5 +160,14 @@ public class TypeInfo
"igInputTextMultiline",
"igInputTextWithHint"
};

public static string GetTypeForBitfield(int size) => size switch
{
_ when size <= 8 => "byte",
_ when size <= 16 => "ushort",
_ when size <= 32 => "uint",
_ when size <= 64 => "ulong",
_ => throw new System.NotSupportedException("Unsupported bitfield size: " + size)
};
}
}
22 changes: 16 additions & 6 deletions src/ImGui.NET/Generated/ImFontGlyph.gen.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,7 @@ namespace ImGuiNET
{
public unsafe partial struct ImFontGlyph
{
public uint Colored;
public uint Visible;
public uint Codepoint;
public uint _bitField_0;
public float AdvanceX;
public float X0;
public float Y0;
Expand All @@ -28,9 +26,21 @@ public unsafe partial struct ImFontGlyphPtr
public static implicit operator ImFontGlyphPtr(ImFontGlyph* nativePtr) => new ImFontGlyphPtr(nativePtr);
public static implicit operator ImFontGlyph* (ImFontGlyphPtr wrappedPtr) => wrappedPtr.NativePtr;
public static implicit operator ImFontGlyphPtr(IntPtr nativePtr) => new ImFontGlyphPtr(nativePtr);
public ref uint Colored => ref Unsafe.AsRef<uint>(&NativePtr->Colored);
public ref uint Visible => ref Unsafe.AsRef<uint>(&NativePtr->Visible);
public ref uint Codepoint => ref Unsafe.AsRef<uint>(&NativePtr->Codepoint);
public uint Colored
{
get => (uint)Util.GetBits(NativePtr->_bitField_0, 0, 1);
set => NativePtr->_bitField_0 = Util.SetBits(NativePtr->_bitField_0, 0, 1, (uint)value);
}
public uint Visible
{
get => (uint)Util.GetBits(NativePtr->_bitField_0, 1, 1);
set => NativePtr->_bitField_0 = Util.SetBits(NativePtr->_bitField_0, 1, 1, (uint)value);
}
public uint Codepoint
{
get => (uint)Util.GetBits(NativePtr->_bitField_0, 2, 30);
set => NativePtr->_bitField_0 = Util.SetBits(NativePtr->_bitField_0, 2, 30, (uint)value);
}
public ref float AdvanceX => ref Unsafe.AsRef<float>(&NativePtr->AdvanceX);
public ref float X0 => ref Unsafe.AsRef<float>(&NativePtr->X0);
public ref float Y0 => ref Unsafe.AsRef<float>(&NativePtr->Y0);
Expand Down
8 changes: 6 additions & 2 deletions src/ImGui.NET/Generated/ImGuiTableColumnSortSpecs.gen.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ public unsafe partial struct ImGuiTableColumnSortSpecs
public uint ColumnUserID;
public short ColumnIndex;
public short SortOrder;
public ImGuiSortDirection SortDirection;
public byte _bitField_0;
}
public unsafe partial struct ImGuiTableColumnSortSpecsPtr
{
Expand All @@ -23,7 +23,11 @@ public unsafe partial struct ImGuiTableColumnSortSpecsPtr
public ref uint ColumnUserID => ref Unsafe.AsRef<uint>(&NativePtr->ColumnUserID);
public ref short ColumnIndex => ref Unsafe.AsRef<short>(&NativePtr->ColumnIndex);
public ref short SortOrder => ref Unsafe.AsRef<short>(&NativePtr->SortOrder);
public ref ImGuiSortDirection SortDirection => ref Unsafe.AsRef<ImGuiSortDirection>(&NativePtr->SortDirection);
public ImGuiSortDirection SortDirection
{
get => (ImGuiSortDirection)Util.GetBits(NativePtr->_bitField_0, 0, 8);
set => NativePtr->_bitField_0 = Util.SetBits(NativePtr->_bitField_0, 0, 8, (byte)value);
}
public void Destroy()
{
ImGuiNative.ImGuiTableColumnSortSpecs_destroy((ImGuiTableColumnSortSpecs*)(NativePtr));
Expand Down
27 changes: 27 additions & 0 deletions src/ImGui.NET/Util.cs
Original file line number Diff line number Diff line change
Expand Up @@ -93,5 +93,32 @@ internal static int GetUtf8(string s, int start, int length, byte* utf8Bytes, in
return Encoding.UTF8.GetBytes(utf16Ptr + start, length, utf8Bytes, utf8ByteCount);
}
}

internal static byte SetBits(byte oldValue, int offset, int bitCount, byte newBits)
{
var mask = (byte)((1 << bitCount) - 1 << offset);
return (byte)((oldValue & ~mask) | (newBits << offset & mask));
}

internal static ushort SetBits(ushort oldValue, int offset, int bitCount, ushort newBits)
{
var mask = (ushort)((1 << bitCount) - 1 << offset);
return (ushort)((oldValue & ~mask) | (newBits << offset & mask));
}

internal static uint SetBits(uint oldValue, int offset, int bitCount, uint newBits)
{
var mask = (uint)((1 << bitCount) - 1 << offset);
return (uint)((oldValue & ~mask) | (newBits << offset & mask));
}

internal static ulong SetBits(ulong oldValue, int offset, int bitCount, ulong newBits)
{
var mask = (ulong)((1 << bitCount) - 1 << offset);
return (ulong)((oldValue & ~mask) | (newBits << offset & mask));
}

internal static ulong GetBits(ulong value, int offset, int bitCount) =>
(value >> offset) & (1UL << bitCount) - 1;
}
}