Initial Commit

This commit is contained in:
2026-05-18 01:12:52 -05:00
commit fc0b04a4bc
13 changed files with 2225 additions and 0 deletions
+162
View File
@@ -0,0 +1,162 @@
using Hexa.NET.ImGui;
namespace SDL3_TestingSuite.SDL3;
public struct FontMetrics
{
public ushort UnitsPerEm;
public short TypoAscender;
public short TypoDescender;
public short TypoLineGap;
public short WinAscent;
public short WinDescent;
public int TypoLineHeight;
public int WinLineHeight;
}
public static class FontFind
{
extension(ImGuiIOPtr io)
{
public unsafe ImFontPtr AddFont(string fontPath)
{
try
{
if (fontPath == null || io.Handle == null) return null;
FileInfo info = new FileInfo(fontPath);
if (!info.Exists || info.Length <= 0) return null;
FontMetrics metrics = FontFind.ReadFontMetrics(fontPath);
float size = FontFind.GetRecommendedPixelSize(metrics);
ImFontConfigPtr config = ImGui.ImFontConfig();
config.FontLoaderFlags |= (uint)ImGuiFreeTypeLoaderFlags.LoadColor;
ImFontPtr font = io.Fonts.AddFontFromFileTTF(fontPath, size, config);
Program.Logger.Log("Added font: " + Path.GetFileName(fontPath));
return font;
}
catch (Exception e)
{
Console.WriteLine(e);
}
return null;
}
public unsafe bool RemoveFont(string? fontName)
{
if (fontName == null || io.Handle == null) return false;
bool flag = false;
ImVector<ImFontPtr> fonts = io.Fonts.Fonts;
List<ImFontPtr> toRemove = new List<ImFontPtr>();
for (int i = 0; i < fonts.Size; i++)
{
ImFontPtr font = fonts[i];
if (font.GetDebugNameS() == fontName)
{
toRemove.Add(font);
flag = true;
}
}
foreach (ImFontPtr font in toRemove)
{
io.Fonts.RemoveFont(font);
Program.Logger.Log("Removed font: " + fontName);
}
return flag;
}
}
public static FontMetrics ReadFontMetrics(string fontPath)
{
byte[] data = File.ReadAllBytes(fontPath);
ushort numTables = ReadU16Be(4);
const int tableDir = 12;
int headOffset = 0;
int os2Offset = 0;
for (int i = 0; i < numTables; i++)
{
int entry = tableDir + i * 16;
string tag = ReadTag(entry);
uint offset = ReadU32Be(entry + 8);
if (tag == "head")
headOffset = (int)offset;
if (tag == "OS/2")
os2Offset = (int)offset;
}
FontMetrics metrics = new FontMetrics();
metrics.UnitsPerEm = ReadU16Be(headOffset + 18);
if (os2Offset != 0)
{
metrics.TypoAscender = ReadS16Be(os2Offset + 68);
metrics.TypoDescender = ReadS16Be(os2Offset + 70);
metrics.TypoLineGap = ReadS16Be(os2Offset + 72);
metrics.WinAscent = ReadS16Be(os2Offset + 74);
metrics.WinDescent = ReadS16Be(os2Offset + 76);
}
metrics.TypoLineHeight =
metrics.TypoAscender - metrics.TypoDescender + metrics.TypoLineGap;
metrics.WinLineHeight =
metrics.WinAscent + metrics.WinDescent;
return metrics;
ushort ReadU16Be(int o)
{
return (ushort)((data[o] << 8) | data[o + 1]);
}
short ReadS16Be(int o)
{
return (short)ReadU16Be(o);
}
uint ReadU32Be(int o)
{
return (uint)((data[o] << 24) | (data[o + 1] << 16) | (data[o + 2] << 8) | data[o + 3]);
}
string ReadTag(int o)
{
char c1 = (char)data[o];
char c2 = (char)data[o + 1];
char c3 = (char)data[o + 2];
char c4 = (char)data[o + 3];
return new string(new char[] { c1, c2, c3, c4 });
}
}
public static int GetRecommendedPixelSize(FontMetrics metrics)
{
if (metrics.UnitsPerEm == 0 || metrics.TypoLineHeight == 0)
return 16;
const float targetLineHeightPx = 18.0f;
float scale = targetLineHeightPx * metrics.UnitsPerEm / metrics.TypoLineHeight;
int size = (int)MathF.Round(scale);
if (size < 10) size = 10;
if (size > 72) size = 72;
return size;
}
}