Skip to content

Commit 13a6113

Browse files
committed
fix: improve ImGui C# font coverage
1 parent 0d58048 commit 13a6113

6 files changed

Lines changed: 138 additions & 46 deletions

File tree

‎StArray.ModManager.Windows/UI/D3D11Renderer.cs‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -132,8 +132,7 @@ void Init(nint sc)
132132
_origWnd = Win32Native.SetWindowLongPtrW(_hwnd, -4, Marshal.GetFunctionPointerForDelegate(_wndDel));
133133

134134
// ImGui
135-
ImGui.CreateContext();
136-
ImGui.GetIO().ConfigFlags |= ImGuiConfigFlags.NavEnableKeyboard | ImGuiConfigFlags.DockingEnable;
135+
((IImGuiRenderer)this).InitImGui();
137136
ImGui_ImplWin32_Init(_hwnd);
138137
ImGui_ImplDX11_Init(_dev, _ctx);
139138
_inited = true; Logger.Info(nameof(D3D11Renderer), "ImGui ready");
556 KB
Binary file not shown.
641 KB
Binary file not shown.
1.45 MB
Binary file not shown.

‎StArray.ModManager/StArray.ModManager.csproj‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,10 @@
2424

2525
<ItemGroup>
2626
<EmbeddedResource Include="Resources\fa-solid-900.ttf" />
27+
<EmbeddedResource Include="Resources\NotoSans-Regular.ttf" />
2728
<EmbeddedResource Include="Resources\NotoSansCJK-Regular.otf" />
29+
<EmbeddedResource Include="Resources\NotoSansSymbols2-Regular.ttf" />
30+
<EmbeddedResource Include="Resources\OpenMoji-black-glyf.ttf" />
2831
</ItemGroup>
2932

3033
<ItemGroup>

‎StArray.ModManager/UI/IImGuiRenderer.cs‎

Lines changed: 134 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -27,72 +27,162 @@ void InitImGui()
2727
ImGui.SetCurrentContext(ImGui.CreateContext());
2828
var io = ImGui.GetIO();
2929
io.ConfigFlags |= ImGuiConfigFlags.NavEnableKeyboard | ImGuiConfigFlags.DockingEnable;
30-
LoadIconFont(io);
31-
LoadEmbeddedFont(io);
32-
// 注意:AddFontFromMemoryTTF 只存指针,Build() 时才真正读取数据
33-
io.Fonts.Build();
34-
// Build() 之后才能安全释放字体内存
35-
FreeFontMemory();
30+
31+
try
32+
{
33+
var hasBaseFont = LoadEmbeddedFont(
34+
io,
35+
"StArray.ModManager.Resources.NotoSansCJK-Regular.otf",
36+
ref _cjkFontPtr,
37+
merge: false,
38+
GetAllUnicodeRanges());
39+
40+
var latinFontIsBase = false;
41+
if (!hasBaseFont)
42+
{
43+
latinFontIsBase = LoadEmbeddedFont(
44+
io,
45+
"StArray.ModManager.Resources.NotoSans-Regular.ttf",
46+
ref _latinFontPtr,
47+
merge: false,
48+
GetAllUnicodeRanges());
49+
hasBaseFont = latinFontIsBase;
50+
}
51+
52+
if (!hasBaseFont)
53+
{
54+
io.Fonts.AddFontDefault();
55+
hasBaseFont = true;
56+
}
57+
58+
if (!latinFontIsBase)
59+
{
60+
LoadEmbeddedFont(
61+
io,
62+
"StArray.ModManager.Resources.NotoSans-Regular.ttf",
63+
ref _latinFontPtr,
64+
merge: true,
65+
GetAllUnicodeRanges());
66+
}
67+
LoadEmbeddedFont(
68+
io,
69+
"StArray.ModManager.Resources.NotoSansSymbols2-Regular.ttf",
70+
ref _symbolsFontPtr,
71+
merge: true,
72+
GetAllUnicodeRanges());
73+
LoadEmbeddedFont(
74+
io,
75+
"StArray.ModManager.Resources.OpenMoji-black-glyf.ttf",
76+
ref _emojiFontPtr,
77+
merge: true,
78+
GetAllUnicodeRanges());
79+
LoadEmbeddedFont(
80+
io,
81+
"StArray.ModManager.Resources.fa-solid-900.ttf",
82+
ref _iconFontPtr,
83+
merge: true,
84+
GetIconRanges());
85+
86+
// AddFontFromMemoryTTF 只保存指针,Build() 时才真正读取数据。
87+
io.Fonts.Build();
88+
}
89+
finally
90+
{
91+
FreeFontMemory();
92+
}
3693
}
3794

38-
private static nint _fontPtr1, _fontPtr2;
95+
private static nint _cjkFontPtr;
96+
private static nint _latinFontPtr;
97+
private static nint _symbolsFontPtr;
98+
private static nint _emojiFontPtr;
99+
private static nint _iconFontPtr;
100+
private static nint _allUnicodeRangesPtr;
101+
private static nint _iconRangesPtr;
39102

40103
private static void FreeFontMemory()
41104
{
42-
if (_fontPtr1 != 0) { Marshal.FreeHGlobal(_fontPtr1); _fontPtr1 = 0; }
43-
if (_fontPtr2 != 0) { Marshal.FreeHGlobal(_fontPtr2); _fontPtr2 = 0; }
105+
Free(ref _cjkFontPtr);
106+
Free(ref _latinFontPtr);
107+
Free(ref _symbolsFontPtr);
108+
Free(ref _emojiFontPtr);
109+
Free(ref _iconFontPtr);
110+
Free(ref _allUnicodeRangesPtr);
111+
Free(ref _iconRangesPtr);
44112
}
45113

46-
private static unsafe void LoadEmbeddedFont(ImGuiIOPtr io)
114+
private static void Free(ref nint ptr)
47115
{
48-
try
49-
{
50-
var asm = typeof(IImGuiRenderer).Assembly;
51-
using var stream = asm.GetManifestResourceStream(
52-
"StArray.ModManager.Resources.NotoSansCJK-Regular.otf");
53-
if (stream == null) return;
116+
if (ptr == 0) return;
117+
Marshal.FreeHGlobal(ptr);
118+
ptr = 0;
119+
}
54120

55-
var ttf = new byte[stream.Length];
56-
stream.ReadExactly(ttf);
57-
_fontPtr1 = Marshal.AllocHGlobal(ttf.Length);
58-
Marshal.Copy(ttf, 0, _fontPtr1, ttf.Length);
121+
private static nint GetAllUnicodeRanges()
122+
{
123+
if (_allUnicodeRangesPtr != 0) return _allUnicodeRangesPtr;
124+
_allUnicodeRangesPtr = AllocateRanges(0x0001, 0xFFFF);
125+
return _allUnicodeRangesPtr;
126+
}
59127

60-
// MergeMode: 中文字形合并到图标基础字体
61-
var cfg = ImGuiNative.ImFontConfig_ImFontConfig();
62-
cfg->MergeMode = 1;
63-
cfg->FontDataOwnedByAtlas = 0; // 自己管理内存,Build() 后释放
128+
private static nint GetIconRanges()
129+
{
130+
if (_iconRangesPtr != 0) return _iconRangesPtr;
131+
_iconRangesPtr = AllocateRanges(0xE000, 0xF8FF);
132+
return _iconRangesPtr;
133+
}
64134

65-
var glyphRanges = io.Fonts.GetGlyphRangesChineseSimplifiedCommon();
66-
io.Fonts.AddFontFromMemoryTTF(_fontPtr1, ttf.Length, 16f, cfg, glyphRanges);
67-
ImGuiNative.ImFontConfig_destroy(cfg);
68-
}
69-
catch { /* 静默跳过 */ }
135+
private static nint AllocateRanges(ushort first, ushort last)
136+
{
137+
var ptr = Marshal.AllocHGlobal(sizeof(ushort) * 3);
138+
Marshal.WriteInt16(ptr, 0, (short)first);
139+
Marshal.WriteInt16(ptr, sizeof(ushort), (short)last);
140+
Marshal.WriteInt16(ptr, sizeof(ushort) * 2, 0);
141+
return ptr;
70142
}
71143

72-
private static unsafe void LoadIconFont(ImGuiIOPtr io)
144+
private static unsafe bool LoadEmbeddedFont(
145+
ImGuiIOPtr io,
146+
string resourceName,
147+
ref nint fontPtr,
148+
bool merge,
149+
nint glyphRanges)
73150
{
74151
try
75152
{
76153
var asm = typeof(IImGuiRenderer).Assembly;
77-
using var stream = asm.GetManifestResourceStream(
78-
"StArray.ModManager.Resources.fa-solid-900.ttf");
79-
if (stream == null) return;
154+
using var stream = asm.GetManifestResourceStream(resourceName);
155+
if (stream == null) return false;
80156

81-
var ttf = new byte[stream.Length];
82-
stream.ReadExactly(ttf);
83-
_fontPtr2 = Marshal.AllocHGlobal(ttf.Length);
84-
Marshal.Copy(ttf, 0, _fontPtr2, ttf.Length);
157+
var fontData = new byte[checked((int)stream.Length)];
158+
stream.ReadExactly(fontData);
159+
fontPtr = Marshal.AllocHGlobal(fontData.Length);
160+
Marshal.Copy(fontData, 0, fontPtr, fontData.Length);
85161

86-
// 基础字体:FontAwesome 7 图标
87162
var cfg = ImGuiNative.ImFontConfig_ImFontConfig();
88-
cfg->FontDataOwnedByAtlas = 0; // 自己管理内存
163+
try
164+
{
165+
cfg->MergeMode = merge ? (byte)1 : (byte)0;
166+
cfg->FontDataOwnedByAtlas = 0;
167+
io.Fonts.AddFontFromMemoryTTF(
168+
fontPtr,
169+
fontData.Length,
170+
16f,
171+
cfg,
172+
glyphRanges);
173+
}
174+
finally
175+
{
176+
ImGuiNative.ImFontConfig_destroy(cfg);
177+
}
89178

90-
ushort[] iconRange = [0xe005, 0xf8ff, 0];
91-
fixed (ushort* r = iconRange)
92-
io.Fonts.AddFontFromMemoryTTF(_fontPtr2, ttf.Length, 16f, cfg, (IntPtr)r);
93-
ImGuiNative.ImFontConfig_destroy(cfg);
179+
return true;
180+
}
181+
catch
182+
{
183+
Free(ref fontPtr);
184+
return false;
94185
}
95-
catch { /* 静默跳过 */ }
96186
}
97187

98188
/// <summary>

0 commit comments

Comments
 (0)