Skip to content

Commit 72448dc

Browse files
committed
Add support for bitfields
1 parent 653ef38 commit 72448dc

File tree

6 files changed

+139
-13
lines changed

6 files changed

+139
-13
lines changed

src/CodeGenerator/ImguiDefinitions.cs

Lines changed: 62 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,14 @@ static int GetInt(JToken token, string key)
2121
if (v == null) return 0;
2222
return v.ToObject<int>();
2323
}
24+
25+
static int? GetOptionalInt(JToken token, string key)
26+
{
27+
var v = token[key];
28+
if (v == null) return null;
29+
return v.ToObject<int>();
30+
}
31+
2432
public void LoadFrom(string directory)
2533
{
2634

@@ -92,7 +100,9 @@ public void LoadFrom(string directory)
92100
v["type"].ToString(),
93101
GetInt(v, "size"),
94102
v["template_type"]?.ToString(),
95-
Enums);
103+
Enums,
104+
typeVariants: null,
105+
GetOptionalInt(v, "bitfield"));
96106
}).Where(tr => tr != null).ToArray();
97107
return new TypeDefinition(name, fields);
98108
}).Where(x => x != null).ToArray();
@@ -302,12 +312,34 @@ class TypeDefinition
302312
{
303313
public string Name { get; }
304314
public TypeReference[] Fields { get; }
315+
public BitField[] BitFields { get; }
305316

306317
public TypeDefinition(string name, TypeReference[] fields)
307318
{
308319
Name = name;
309320
Fields = fields;
321+
322+
var bitFields = new List<BitField>();
323+
int bitFieldStartI = -1;
324+
for (int i = 0; i < fields.Length; i++)
325+
{
326+
if (fields[i].BitSize.HasValue && bitFieldStartI < 0)
327+
bitFieldStartI = i;
328+
329+
if (!fields[i].BitSize.HasValue && bitFieldStartI >= 0)
330+
{
331+
bitFields.Add(new BitField(bitFields.Count, fields[bitFieldStartI..i]));
332+
bitFieldStartI = -1;
333+
}
334+
}
335+
if (bitFieldStartI >= 0)
336+
bitFields.Add(new BitField(bitFields.Count, fields[bitFieldStartI..]));
337+
BitFields = bitFields.ToArray();
310338
}
339+
340+
public BitField GetBitFieldContaining(TypeReference field) =>
341+
BitFields.FirstOrDefault(bitField => bitField.Fields.Contains(field))
342+
?? throw new ArgumentException("Given is not part of any bit field");
311343
}
312344

313345
class TypeReference
@@ -319,17 +351,18 @@ class TypeReference
319351
public bool IsFunctionPointer { get; }
320352
public string[] TypeVariants { get; }
321353
public bool IsEnum { get; }
354+
public int? BitSize { get; }
322355

323356
public TypeReference(string name, string type, int asize, EnumDefinition[] enums)
324-
: this(name, type, asize, null, enums, null) { }
357+
: this(name, type, asize, null, enums, null, null) { }
325358

326359
public TypeReference(string name, string type, int asize, EnumDefinition[] enums, string[] typeVariants)
327-
: this(name, type, asize, null, enums, typeVariants) { }
360+
: this(name, type, asize, null, enums, typeVariants, null) { }
328361

329362
public TypeReference(string name, string type, int asize, string templateType, EnumDefinition[] enums)
330-
: this(name, type, asize, templateType, enums, null) { }
363+
: this(name, type, asize, templateType, enums, null, null) { }
331364

332-
public TypeReference(string name, string type, int asize, string templateType, EnumDefinition[] enums, string[] typeVariants)
365+
public TypeReference(string name, string type, int asize, string templateType, EnumDefinition[] enums, string[] typeVariants, int? bitSize)
333366
{
334367
Name = name;
335368
Type = type.Replace("const", string.Empty).Trim();
@@ -376,6 +409,8 @@ public TypeReference(string name, string type, int asize, string templateType, E
376409
TypeVariants = typeVariants;
377410

378411
IsEnum = enums.Any(t => t.Name == type || t.FriendlyName == type || TypeInfo.WellKnownEnums.Contains(type));
412+
413+
BitSize = bitSize;
379414
}
380415

381416
private int ParseSizeString(string sizePart, EnumDefinition[] enums)
@@ -419,6 +454,28 @@ public TypeReference WithVariant(int variantIndex, EnumDefinition[] enums)
419454
}
420455
}
421456

457+
class BitField
458+
{
459+
public string Name { get; }
460+
public string Type { get; }
461+
public TypeReference[] Fields { get; }
462+
463+
public BitField(int index, IEnumerable<TypeReference> fields)
464+
{
465+
Name = $"_bitField_{index}";
466+
Fields = fields.ToArray();
467+
Type = TypeInfo.GetTypeForBitfield(fields.Sum(f => f.BitSize.Value));
468+
}
469+
470+
public int OffsetOf(TypeReference field)
471+
{
472+
var fieldIndex = Array.IndexOf(Fields, field);
473+
if (fieldIndex < 0)
474+
throw new ArgumentException("Given field is not part of the bit field");
475+
return Fields.Take(fieldIndex).Sum(f => f.BitSize.Value);
476+
}
477+
}
478+
422479
class FunctionDefinition
423480
{
424481
public string Name { get; }

src/CodeGenerator/Program.cs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,14 @@ static void Main(string[] args)
134134
}
135135
}
136136
}
137+
else if (field.BitSize.HasValue)
138+
{
139+
var bitField = td.GetBitFieldContaining(field);
140+
if (bitField.OffsetOf(field) > 0)
141+
continue;
142+
143+
writer.WriteLine($"public {bitField.Type} {bitField.Name};");
144+
}
137145
else
138146
{
139147
writer.WriteLine($"public {typeStr} {field.Name};");
@@ -165,6 +173,17 @@ static void Main(string[] args)
165173
string addrTarget = TypeInfo.LegalFixedTypes.Contains(rawType) ? $"NativePtr->{field.Name}" : $"&NativePtr->{field.Name}_0";
166174
writer.WriteLine($"public RangeAccessor<{typeStr}> {field.Name} => new RangeAccessor<{typeStr}>({addrTarget}, {field.ArraySize});");
167175
}
176+
else if (field.BitSize.HasValue)
177+
{
178+
var bitField = td.GetBitFieldContaining(field);
179+
var offset = bitField.OffsetOf(field);
180+
var mask = (ulong)(1 << field.BitSize) - 1 << offset;
181+
182+
writer.PushBlock($"public {typeStr} {field.Name}");
183+
writer.WriteLine($"get => ({typeStr})Util.GetBits(NativePtr->{bitField.Name}, {offset}, {field.BitSize});");
184+
writer.WriteLine($"set => Util.SetBits(NativePtr->{bitField.Name}, {offset}, {field.BitSize}, ({bitField.Type})value);");
185+
writer.PopBlock();
186+
}
168187
else if (typeStr.Contains("ImVector"))
169188
{
170189
string vectorElementType = GetTypeString(field.TemplateType, false);

src/CodeGenerator/TypeInfo.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,5 +142,14 @@ public class TypeInfo
142142
"igCalcTextSize",
143143
"igInputTextWithHint"
144144
};
145+
146+
public static string GetTypeForBitfield(int size) => size switch
147+
{
148+
_ when size <= 8 => "byte",
149+
_ when size <= 16 => "ushort",
150+
_ when size <= 32 => "uint",
151+
_ when size <= 64 => "ulong",
152+
_ => throw new System.NotSupportedException("Unsupported bitfield size: " + size)
153+
};
145154
}
146155
}

src/ImGui.NET/Generated/ImFontGlyph.gen.cs

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,7 @@ namespace ImGuiNET
77
{
88
public unsafe partial struct ImFontGlyph
99
{
10-
public uint Colored;
11-
public uint Visible;
12-
public uint Codepoint;
10+
public uint _bitField_0;
1311
public float AdvanceX;
1412
public float X0;
1513
public float Y0;
@@ -28,9 +26,21 @@ public unsafe partial struct ImFontGlyphPtr
2826
public static implicit operator ImFontGlyphPtr(ImFontGlyph* nativePtr) => new ImFontGlyphPtr(nativePtr);
2927
public static implicit operator ImFontGlyph* (ImFontGlyphPtr wrappedPtr) => wrappedPtr.NativePtr;
3028
public static implicit operator ImFontGlyphPtr(IntPtr nativePtr) => new ImFontGlyphPtr(nativePtr);
31-
public ref uint Colored => ref Unsafe.AsRef<uint>(&NativePtr->Colored);
32-
public ref uint Visible => ref Unsafe.AsRef<uint>(&NativePtr->Visible);
33-
public ref uint Codepoint => ref Unsafe.AsRef<uint>(&NativePtr->Codepoint);
29+
public uint Colored
30+
{
31+
get => (uint)Util.GetBits(NativePtr->_bitField_0, 0, 1);
32+
set => Util.SetBits(NativePtr->_bitField_0, 0, 1, (uint)value);
33+
}
34+
public uint Visible
35+
{
36+
get => (uint)Util.GetBits(NativePtr->_bitField_0, 1, 1);
37+
set => Util.SetBits(NativePtr->_bitField_0, 1, 1, (uint)value);
38+
}
39+
public uint Codepoint
40+
{
41+
get => (uint)Util.GetBits(NativePtr->_bitField_0, 2, 30);
42+
set => Util.SetBits(NativePtr->_bitField_0, 2, 30, (uint)value);
43+
}
3444
public ref float AdvanceX => ref Unsafe.AsRef<float>(&NativePtr->AdvanceX);
3545
public ref float X0 => ref Unsafe.AsRef<float>(&NativePtr->X0);
3646
public ref float Y0 => ref Unsafe.AsRef<float>(&NativePtr->Y0);

src/ImGui.NET/Generated/ImGuiTableColumnSortSpecs.gen.cs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ public unsafe partial struct ImGuiTableColumnSortSpecs
1010
public uint ColumnUserID;
1111
public short ColumnIndex;
1212
public short SortOrder;
13-
public ImGuiSortDirection SortDirection;
13+
public byte _bitField_0;
1414
}
1515
public unsafe partial struct ImGuiTableColumnSortSpecsPtr
1616
{
@@ -23,7 +23,11 @@ public unsafe partial struct ImGuiTableColumnSortSpecsPtr
2323
public ref uint ColumnUserID => ref Unsafe.AsRef<uint>(&NativePtr->ColumnUserID);
2424
public ref short ColumnIndex => ref Unsafe.AsRef<short>(&NativePtr->ColumnIndex);
2525
public ref short SortOrder => ref Unsafe.AsRef<short>(&NativePtr->SortOrder);
26-
public ref ImGuiSortDirection SortDirection => ref Unsafe.AsRef<ImGuiSortDirection>(&NativePtr->SortDirection);
26+
public ImGuiSortDirection SortDirection
27+
{
28+
get => (ImGuiSortDirection)Util.GetBits(NativePtr->_bitField_0, 0, 8);
29+
set => Util.SetBits(NativePtr->_bitField_0, 0, 8, (byte)value);
30+
}
2731
public void Destroy()
2832
{
2933
ImGuiNative.ImGuiTableColumnSortSpecs_destroy((ImGuiTableColumnSortSpecs*)(NativePtr));

src/ImGui.NET/Util.cs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,5 +68,32 @@ internal static int GetUtf8(string s, int start, int length, byte* utf8Bytes, in
6868
return Encoding.UTF8.GetBytes(utf16Ptr + start, length, utf8Bytes, utf8ByteCount);
6969
}
7070
}
71+
72+
internal static byte SetBits(byte oldValue, int offset, int bitCount, byte newBits)
73+
{
74+
var mask = (byte)((1 << bitCount) - 1 << offset);
75+
return (byte)((oldValue & ~mask) | (newBits << offset & mask));
76+
}
77+
78+
internal static ushort SetBits(ushort oldValue, int offset, int bitCount, ushort newBits)
79+
{
80+
var mask = (ushort)((1 << bitCount) - 1 << offset);
81+
return (ushort)((oldValue & ~mask) | (newBits << offset & mask));
82+
}
83+
84+
internal static uint SetBits(uint oldValue, int offset, int bitCount, uint newBits)
85+
{
86+
var mask = (uint)((1 << bitCount) - 1 << offset);
87+
return (uint)((oldValue & ~mask) | (newBits << offset & mask));
88+
}
89+
90+
internal static ulong SetBits(byte oldValue, int offset, int bitCount, ulong newBits)
91+
{
92+
var mask = (ulong)((1 << bitCount) - 1 << offset);
93+
return (ulong)((oldValue & ~mask) | (newBits << offset & mask));
94+
}
95+
96+
internal static ulong GetBits(ulong value, int offset, int bitCount) =>
97+
(value >> offset) & (1UL << bitCount) - 1;
7198
}
7299
}

0 commit comments

Comments
 (0)