diff --git a/src/CodeGenerator/ImguiDefinitions.cs b/src/CodeGenerator/ImguiDefinitions.cs index 23edaee5..e0b2c612 100644 --- a/src/CodeGenerator/ImguiDefinitions.cs +++ b/src/CodeGenerator/ImguiDefinitions.cs @@ -22,6 +22,14 @@ static int GetInt(JToken token, string key) if (v == null) return 0; return v.ToObject(); } + + static int? GetOptionalInt(JToken token, string key) + { + var v = token[key]; + if (v == null) return null; + return v.ToObject(); + } + public void LoadFrom(string directory) { @@ -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(); @@ -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(); + 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 @@ -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(); @@ -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) @@ -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 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; } diff --git a/src/CodeGenerator/Program.cs b/src/CodeGenerator/Program.cs index 8597a718..468c32cc 100644 --- a/src/CodeGenerator/Program.cs +++ b/src/CodeGenerator/Program.cs @@ -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};"); @@ -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); diff --git a/src/CodeGenerator/TypeInfo.cs b/src/CodeGenerator/TypeInfo.cs index 45c89300..b25c405f 100644 --- a/src/CodeGenerator/TypeInfo.cs +++ b/src/CodeGenerator/TypeInfo.cs @@ -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) + }; } } \ No newline at end of file diff --git a/src/ImGui.NET/Generated/ImFontGlyph.gen.cs b/src/ImGui.NET/Generated/ImFontGlyph.gen.cs index 8a78d6f3..04f92d9b 100644 --- a/src/ImGui.NET/Generated/ImFontGlyph.gen.cs +++ b/src/ImGui.NET/Generated/ImFontGlyph.gen.cs @@ -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; @@ -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(&NativePtr->Colored); - public ref uint Visible => ref Unsafe.AsRef(&NativePtr->Visible); - public ref uint Codepoint => ref Unsafe.AsRef(&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(&NativePtr->AdvanceX); public ref float X0 => ref Unsafe.AsRef(&NativePtr->X0); public ref float Y0 => ref Unsafe.AsRef(&NativePtr->Y0); diff --git a/src/ImGui.NET/Generated/ImGuiTableColumnSortSpecs.gen.cs b/src/ImGui.NET/Generated/ImGuiTableColumnSortSpecs.gen.cs index ef1d61bd..cdd53b95 100644 --- a/src/ImGui.NET/Generated/ImGuiTableColumnSortSpecs.gen.cs +++ b/src/ImGui.NET/Generated/ImGuiTableColumnSortSpecs.gen.cs @@ -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 { @@ -23,7 +23,11 @@ public unsafe partial struct ImGuiTableColumnSortSpecsPtr public ref uint ColumnUserID => ref Unsafe.AsRef(&NativePtr->ColumnUserID); public ref short ColumnIndex => ref Unsafe.AsRef(&NativePtr->ColumnIndex); public ref short SortOrder => ref Unsafe.AsRef(&NativePtr->SortOrder); - public ref ImGuiSortDirection SortDirection => ref Unsafe.AsRef(&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)); diff --git a/src/ImGui.NET/Util.cs b/src/ImGui.NET/Util.cs index 438948c8..cb372cfc 100644 --- a/src/ImGui.NET/Util.cs +++ b/src/ImGui.NET/Util.cs @@ -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; } }