Optimized Font Loading
System fonts only load if no glyph is found in the already loaded fonts. fixes #2
This commit is contained in:
parent
7d32666095
commit
4a958ae060
@ -10,7 +10,7 @@
|
||||
<IncludeSymbols>False</IncludeSymbols>
|
||||
<RepositoryUrl>https://git.jacobtech.com/JacobTech.com/GraphicsManager</RepositoryUrl>
|
||||
<RepositoryType>git</RepositoryType>
|
||||
<Version>1.0.0-beta1</Version>
|
||||
<Version>1.0.1-beta01</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -1,25 +1,48 @@
|
||||
using System.Diagnostics;
|
||||
using System.Reflection;
|
||||
using System.Security.Cryptography;
|
||||
using SharpFont;
|
||||
|
||||
namespace GraphicsManager.Objects.Core;
|
||||
|
||||
public class Font
|
||||
{
|
||||
private static List<Face>? System = null;
|
||||
private List<Face> _Faces = new();
|
||||
private Library lib;
|
||||
|
||||
internal Font()
|
||||
internal static Library lib = new();
|
||||
public IReadOnlyList<Face> Fonts => _Faces.AsReadOnly();
|
||||
internal static Dictionary<string, Face> AllFileFonts = new();
|
||||
internal static Dictionary<byte[], Face> AllMemoryFonts = new();
|
||||
internal static List<string>? _SystemPre = null;
|
||||
private static List<Font> AllFonts = new();
|
||||
private static bool Backup = false;
|
||||
|
||||
internal void AddSystemFontFace(string path)
|
||||
{
|
||||
Console.WriteLine("Added font: " + path);
|
||||
if (!AllFileFonts.ContainsKey(path)) AllFileFonts.Add(path, new(lib, path, 0));
|
||||
if (!_Faces.Contains(AllFileFonts[path]))
|
||||
{
|
||||
foreach (Font ft in AllFonts)
|
||||
{
|
||||
ft._Faces.Add(AllFileFonts[path]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Font()
|
||||
{
|
||||
Name = null!;
|
||||
Assembly = null!;
|
||||
Embeded = false;
|
||||
if (lib is null) lib = new();
|
||||
//TODO add more systemfont dection methods
|
||||
if (System is null)
|
||||
if (!Backup)
|
||||
{
|
||||
System = new();
|
||||
AllMemoryFonts.Add(SHA256.HashData(Tools.GetResourceBytes("GraphicsManager.Resources.Fonts.TektonPro-Regular.otf")), new Face(lib, Tools.GetResourceBytes("GraphicsManager.Resources.Fonts.TektonPro-Regular.otf"), 0));
|
||||
Backup = true;
|
||||
}
|
||||
if (_SystemPre is null)
|
||||
{
|
||||
_SystemPre = new();
|
||||
if (OperatingSystem.IsLinux())
|
||||
{
|
||||
try
|
||||
@ -38,7 +61,7 @@ public class Font
|
||||
string[] files = proc.StandardOutput.ReadToEnd().Split($": {Environment.NewLine}");
|
||||
for (int i = 0; i < files.Length; i++)
|
||||
{
|
||||
System!.Add(new Face(lib, files[i], 0));
|
||||
_SystemPre.Add(files[i]);
|
||||
}
|
||||
}
|
||||
catch
|
||||
@ -46,11 +69,7 @@ public class Font
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < System!.Count; i++) _Faces.Add(System![i]);
|
||||
//TODO add a reserved backup font
|
||||
}
|
||||
public IReadOnlyList<Face> Faces => _Faces.AsReadOnly();
|
||||
public void SetEmbeddedFont(string Font, Assembly? Assembly = null)
|
||||
{
|
||||
_ = Font ?? throw new ArgumentNullException(nameof(Font));
|
||||
@ -59,9 +78,14 @@ public class Font
|
||||
byte[] f = (Assembly is null
|
||||
? Tools.GetResourceBytes(Base + Font)
|
||||
: Tools.GetResourceBytes(Assembly!, $"{Base}{Font}"));
|
||||
if (HasTopFont) _Faces[0] = new Face(lib, f, 0);
|
||||
else _Faces.Insert(0, new Face(lib, f, 0));
|
||||
HasTopFont = true;
|
||||
byte[] hash = SHA256.HashData(f);
|
||||
if (AllMemoryFonts.ContainsKey(hash)) AllMemoryFonts.Add(hash, new(lib, f, 0));
|
||||
if (!_Faces.Contains(AllMemoryFonts[hash])) _Faces.Insert(0, AllMemoryFonts[hash]);
|
||||
else
|
||||
{
|
||||
_Faces.Remove(AllMemoryFonts[hash]);
|
||||
_Faces.Insert(0, AllMemoryFonts[hash]);
|
||||
}
|
||||
this.Assembly = Assembly;
|
||||
this.Embeded = true;
|
||||
this.Name = Font;
|
||||
@ -77,17 +101,28 @@ public class Font
|
||||
Name = Font,
|
||||
HasTopFont = true
|
||||
};
|
||||
AllFonts.Add(fontclass);
|
||||
string Base = "GraphicsManager.Resources.Fonts.";
|
||||
if (Assembly is not null) Base = string.Empty;
|
||||
byte[] f = (Assembly is null
|
||||
? Tools.GetResourceBytes(Base + Font)
|
||||
: Tools.GetResourceBytes(Assembly!, $"{Base}{Font}"));
|
||||
fontclass._Faces.Insert(0, new Face(fontclass.lib, f, 0));
|
||||
byte[] hash = SHA256.HashData(f);
|
||||
if (AllMemoryFonts.ContainsKey(hash)) AllMemoryFonts.Add(hash, new(lib, f, 0));
|
||||
fontclass._Faces.Insert(0, AllMemoryFonts[hash]);
|
||||
return fontclass;
|
||||
}
|
||||
|
||||
public static Font MakeFontFromSystem(uint PixelHeight = 20) => new Font() { PixelHeight = PixelHeight};
|
||||
|
||||
private static Font? Cache = null;
|
||||
public static Font MakeFontFromSystem(uint PixelHeight = 20)
|
||||
{
|
||||
if (Cache is null)
|
||||
{
|
||||
Cache = new() { PixelHeight = PixelHeight };
|
||||
AllFonts.Add(Cache);
|
||||
}
|
||||
return Cache;
|
||||
}
|
||||
public static Font MakeFontFromFile(string Font)
|
||||
{
|
||||
_ = Font ?? throw new ArgumentNullException(nameof(Font));
|
||||
@ -98,7 +133,8 @@ public class Font
|
||||
Name = Font,
|
||||
HasTopFont = true
|
||||
};
|
||||
fontclass._Faces.Insert(0, new Face(fontclass.lib, Font, 0));
|
||||
AllFonts.Add(fontclass);
|
||||
fontclass._Faces.Insert(0, new Face(lib, Font, 0));
|
||||
return fontclass;
|
||||
}
|
||||
|
||||
|
@ -1,12 +1,24 @@
|
||||
using GraphicsManager.Structs;
|
||||
using OpenTK.Graphics.OpenGL4;
|
||||
using OpenTK.Graphics.ES30;
|
||||
using OpenTK.Mathematics;
|
||||
using OpenTK.Windowing.Desktop;
|
||||
using SharpFont;
|
||||
using SixLabors.ImageSharp;
|
||||
using SixLabors.ImageSharp.PixelFormats;
|
||||
using SixLabors.ImageSharp.Processing;
|
||||
using GL = OpenTK.Graphics.OpenGL4.GL;
|
||||
using Image = SixLabors.ImageSharp.Image;
|
||||
using PixelFormat = OpenTK.Graphics.OpenGL4.PixelFormat;
|
||||
using PixelInternalFormat = OpenTK.Graphics.OpenGL4.PixelInternalFormat;
|
||||
using PixelStoreParameter = OpenTK.Graphics.OpenGL4.PixelStoreParameter;
|
||||
using PixelType = OpenTK.Graphics.OpenGL4.PixelType;
|
||||
using TextureMagFilter = OpenTK.Graphics.OpenGL4.TextureMagFilter;
|
||||
using TextureMinFilter = OpenTK.Graphics.OpenGL4.TextureMinFilter;
|
||||
using TextureParameterName = OpenTK.Graphics.OpenGL4.TextureParameterName;
|
||||
using TextureTarget = OpenTK.Graphics.OpenGL4.TextureTarget;
|
||||
using TextureUnit = OpenTK.Graphics.OpenGL4.TextureUnit;
|
||||
using TextureWrapMode = OpenTK.Graphics.OpenGL4.TextureWrapMode;
|
||||
using VertexAttribPointerType = OpenTK.Graphics.OpenGL4.VertexAttribPointerType;
|
||||
|
||||
namespace GraphicsManager.Objects.Core;
|
||||
|
||||
@ -46,35 +58,35 @@ public class Texture
|
||||
{
|
||||
}
|
||||
|
||||
internal static Character GetChar(Font l, char charter, Face[] faces)
|
||||
internal static Character GetChar(Font l, char charter)
|
||||
{
|
||||
Character t = new();
|
||||
for (int i = 0; i < faces.Length; i++)
|
||||
int last = 0;
|
||||
for (int i = 0; i < l.Fonts.Count; i++)
|
||||
{
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
faces[i].SetPixelSizes(0, l.PixelHeight);
|
||||
l.Fonts[i].SetPixelSizes(0, l.PixelHeight);
|
||||
last = i;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
faces[i].SelectCharmap(Encoding.Unicode);
|
||||
l.Fonts[i].SelectCharmap(Encoding.Unicode);
|
||||
ushort temp = ((ushort)charter);
|
||||
if (faces[i].GetCharIndex(temp) == 0) continue;
|
||||
faces[i].LoadChar(temp, LoadFlags.Render, LoadTarget.Normal);
|
||||
GlyphSlot glyph = faces[i].Glyph;
|
||||
if (l.Fonts[i].GetCharIndex(temp) == 0) continue;
|
||||
l.Fonts[i].LoadChar(temp, LoadFlags.Render, LoadTarget.Normal);
|
||||
GlyphSlot glyph = l.Fonts[i].Glyph;
|
||||
FTBitmap bitmap = glyph.Bitmap;
|
||||
|
||||
t = new()
|
||||
return new()
|
||||
{
|
||||
Size = new Vector2(bitmap.Width, bitmap.Rows),
|
||||
Bearing = new Vector2(glyph.BitmapLeft, glyph.BitmapTop),
|
||||
Advance = glyph.Advance.X.Value,
|
||||
};
|
||||
return t;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@ -82,14 +94,65 @@ public class Texture
|
||||
continue;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < Font._SystemPre.Count; i++)
|
||||
{
|
||||
try
|
||||
{
|
||||
Face tmp = new(Font.lib, Font._SystemPre[i], 0);
|
||||
try
|
||||
{
|
||||
tmp.SetPixelSizes(0, l.PixelHeight);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
tmp.Dispose();
|
||||
continue;
|
||||
}
|
||||
tmp.SelectCharmap(Encoding.Unicode);
|
||||
ushort temp2 = ((ushort)charter);
|
||||
if (tmp.GetCharIndex(temp2) == 0)
|
||||
{
|
||||
tmp.Dispose();
|
||||
continue;
|
||||
}
|
||||
tmp.LoadChar(temp2, LoadFlags.Render, LoadTarget.Normal);
|
||||
GlyphSlot glyph2 = tmp.Glyph;
|
||||
FTBitmap bitmap2 = glyph2.Bitmap;
|
||||
l.AddSystemFontFace(Font._SystemPre[i]);
|
||||
return new()
|
||||
{
|
||||
Size = new Vector2(bitmap2.Width, bitmap2.Rows),
|
||||
Bearing = new Vector2(glyph2.BitmapLeft, glyph2.BitmapTop),
|
||||
Advance = glyph2.Advance.X.Value,
|
||||
};
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine(ex);
|
||||
}
|
||||
}
|
||||
l.Fonts[last].SetPixelSizes(0, l.PixelHeight);
|
||||
|
||||
l.Fonts[last].SelectCharmap(Encoding.Unicode);
|
||||
ushort temp22 = ((ushort)charter);
|
||||
l.Fonts[last].LoadChar(temp22, LoadFlags.Render, LoadTarget.Normal);
|
||||
GlyphSlot glyph22 = l.Fonts[0].Glyph;
|
||||
FTBitmap bitmap22 = glyph22.Bitmap;
|
||||
|
||||
return new()
|
||||
{
|
||||
Size = new Vector2(bitmap22.Width, bitmap22.Rows),
|
||||
Bearing = new Vector2(glyph22.BitmapLeft, glyph22.BitmapTop),
|
||||
Advance = (int)glyph22.Advance.X.Value,
|
||||
};
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
internal static Texture TextureForChar(IGLFWGraphicsContext con, Font l, char charter, Face[] faces)
|
||||
internal static Texture TextureForChar(IGLFWGraphicsContext con, Font l, char charter)
|
||||
{
|
||||
Texture t = new();
|
||||
for (int i = 0; i < faces.Length; i++)
|
||||
Texture? t = null;
|
||||
int last = 0;
|
||||
for (int i = 0; i < l.Fonts.Count; i++)
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -97,7 +160,8 @@ public class Texture
|
||||
if (Label._characters[con][l].ContainsKey(charter)) return Label._characters[con][l][(ushort)charter].Texture;
|
||||
try
|
||||
{
|
||||
faces[i].SetPixelSizes(0, l.PixelHeight);
|
||||
l.Fonts[i].SetPixelSizes(0, l.PixelHeight);
|
||||
last = i;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@ -108,13 +172,13 @@ public class Texture
|
||||
GL.PixelStore(PixelStoreParameter.UnpackAlignment, 1);
|
||||
|
||||
GL.ActiveTexture(TextureUnit.Texture0);
|
||||
faces[i].SelectCharmap(Encoding.Unicode);
|
||||
l.Fonts[i].SelectCharmap(Encoding.Unicode);
|
||||
ushort temp = ((ushort)charter);
|
||||
if (faces[i].GetCharIndex(temp) == 0) continue;
|
||||
faces[i].LoadChar(temp, LoadFlags.Render, LoadTarget.Normal);
|
||||
GlyphSlot glyph = faces[i].Glyph;
|
||||
if (l.Fonts[i].GetCharIndex(temp) == 0) continue;
|
||||
l.Fonts[i].LoadChar(temp, LoadFlags.Render, LoadTarget.Normal);
|
||||
GlyphSlot glyph = l.Fonts[i].Glyph;
|
||||
FTBitmap bitmap = glyph.Bitmap;
|
||||
|
||||
t = new();
|
||||
t.handel = GL.GenTexture();
|
||||
GL.BindTexture(TextureTarget.Texture2D, t.handel);
|
||||
GL.TexImage2D(TextureTarget.Texture2D, 0,
|
||||
@ -131,6 +195,7 @@ public class Texture
|
||||
};
|
||||
|
||||
Label._characters[con][l].Add(temp, cha);
|
||||
return t;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@ -139,6 +204,91 @@ public class Texture
|
||||
}
|
||||
}
|
||||
|
||||
if (t is null)
|
||||
{
|
||||
for (int i = 0; i < Font._SystemPre.Count; i++)
|
||||
{
|
||||
try
|
||||
{
|
||||
Face tmp = new(Font.lib, Font._SystemPre[i], 0);
|
||||
try
|
||||
{
|
||||
tmp.SetPixelSizes(0, l.PixelHeight);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
tmp.Dispose();
|
||||
continue;
|
||||
}
|
||||
GL.PixelStore(PixelStoreParameter.UnpackAlignment, 1);
|
||||
|
||||
GL.ActiveTexture(TextureUnit.Texture0);
|
||||
tmp.SelectCharmap(Encoding.Unicode);
|
||||
ushort temp2 = ((ushort)charter);
|
||||
if (tmp.GetCharIndex(temp2) == 0)
|
||||
{
|
||||
tmp.Dispose();
|
||||
continue;
|
||||
}
|
||||
tmp.LoadChar(temp2, LoadFlags.Render, LoadTarget.Normal);
|
||||
GlyphSlot glyph2 = tmp.Glyph;
|
||||
FTBitmap bitmap2 = glyph2.Bitmap;
|
||||
l.AddSystemFontFace(Font._SystemPre[i]);
|
||||
t = new();
|
||||
t.handel = GL.GenTexture();
|
||||
GL.BindTexture(TextureTarget.Texture2D, t.handel);
|
||||
GL.TexImage2D(TextureTarget.Texture2D, 0,
|
||||
PixelInternalFormat.R8, bitmap2.Width, bitmap2.Rows, 0,
|
||||
PixelFormat.Red, PixelType.UnsignedByte, bitmap2.Buffer);
|
||||
Character cha2 = new()
|
||||
{
|
||||
Size = new Vector2(bitmap2.Width, bitmap2.Rows),
|
||||
Bearing = new Vector2(glyph2.BitmapLeft, glyph2.BitmapTop),
|
||||
Advance = (int)glyph2.Advance.X.Value,
|
||||
Texture = t,
|
||||
};
|
||||
|
||||
Label._characters[con][l].Add(temp2, cha2);
|
||||
return t;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine(ex);
|
||||
}
|
||||
}
|
||||
if (!Label._characters[con].ContainsKey(l)) Label._characters[con].Add(l, new Dictionary<uint, Character>());
|
||||
if (Label._characters[con][l].ContainsKey(charter)) return Label._characters[con][l][(ushort)charter].Texture;
|
||||
l.Fonts[last].SetPixelSizes(0, l.PixelHeight);
|
||||
|
||||
|
||||
GL.PixelStore(PixelStoreParameter.UnpackAlignment, 1);
|
||||
|
||||
GL.ActiveTexture(TextureUnit.Texture0);
|
||||
l.Fonts[last].SelectCharmap(Encoding.Unicode);
|
||||
ushort temp = ((ushort)charter);
|
||||
l.Fonts[last].LoadChar(temp, LoadFlags.Render, LoadTarget.Normal);
|
||||
GlyphSlot glyph = l.Fonts[0].Glyph;
|
||||
FTBitmap bitmap = glyph.Bitmap;
|
||||
if (t is null) t = new();
|
||||
else return t;
|
||||
t.handel = GL.GenTexture();
|
||||
GL.BindTexture(TextureTarget.Texture2D, t.handel);
|
||||
GL.TexImage2D(TextureTarget.Texture2D, 0,
|
||||
PixelInternalFormat.R8, bitmap.Width, bitmap.Rows, 0,
|
||||
PixelFormat.Red, PixelType.UnsignedByte, bitmap.Buffer);
|
||||
|
||||
|
||||
Character cha = new()
|
||||
{
|
||||
Size = new Vector2(bitmap.Width, bitmap.Rows),
|
||||
Bearing = new Vector2(glyph.BitmapLeft, glyph.BitmapTop),
|
||||
Advance = (int)glyph.Advance.X.Value,
|
||||
Texture = t,
|
||||
};
|
||||
|
||||
Label._characters[con][l].Add(temp, cha);
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
|
@ -15,7 +15,7 @@ namespace GraphicsManager.Objects;
|
||||
public class Label : IRenderObject
|
||||
{
|
||||
public static readonly Dictionary<IGLFWGraphicsContext, Shader> DefaultTextShader = new();
|
||||
public static readonly Font DefaultFont = new();
|
||||
public static readonly Font DefaultFont = Font.MakeFontFromSystem();
|
||||
public ContextMenu? ContextMenu { get; set; } = null;
|
||||
public IParent? Parent { get; private set; }
|
||||
public ObjectAnchor Anchor { get; set; } = ObjectAnchor.Left | ObjectAnchor.Top;
|
||||
@ -74,7 +74,7 @@ public class Label : IRenderObject
|
||||
character = value[i];
|
||||
else
|
||||
character = PasswordChar.Value;
|
||||
Character cha = Texture.GetChar(Font, character, Font.Faces.ToArray());
|
||||
Character cha = Texture.GetChar(Font, character);
|
||||
|
||||
if (character == '\n')
|
||||
{
|
||||
@ -155,9 +155,10 @@ public class Label : IRenderObject
|
||||
c = PasswordChar.Value;
|
||||
if (!_characters[Window!.Context][Font].ContainsKey(c))
|
||||
{
|
||||
var f = Texture.TextureForChar(Window!.Context, Font, c, Font.Faces.ToArray());
|
||||
var f = Texture.TextureForChar(Window!.Context, Font, c);
|
||||
f.LoadText();
|
||||
}
|
||||
if (!_characters[Window!.Context][Font].ContainsKey(c)) continue;
|
||||
Character ch = _characters[Window!.Context][Font][c];
|
||||
int maxx = 0;
|
||||
if (c == '\n')
|
||||
|
Loading…
Reference in New Issue
Block a user