Initial Commit
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user