189 lines
6.4 KiB
C#
189 lines
6.4 KiB
C#
using System.Diagnostics;
|
|
using System.Drawing;
|
|
using System.Numerics;
|
|
using BlurgText;
|
|
using OpenTK.Graphics.OpenGL;
|
|
using OPENGL = OpenTK.Graphics.OpenGL;
|
|
|
|
namespace Dashboard.Drawing.OpenGL.Text
|
|
{
|
|
public class BlurgEngine : IResourceManager, IGLDisposable, ITypeSetter
|
|
{
|
|
public string Name { get; } = "BlurgEngine";
|
|
public Blurg Blurg { get; }
|
|
public bool SystemFontsEnabled { get; }
|
|
|
|
private readonly List<int> _textures = new List<int>();
|
|
|
|
public BlurgEngine() : this(false)
|
|
{
|
|
}
|
|
|
|
private BlurgEngine(bool global)
|
|
{
|
|
if (global)
|
|
Blurg = new Blurg(AllocateTextureGlobal, UpdateTextureGlobal);
|
|
else
|
|
Blurg = new Blurg(AllocateTexture, UpdateTexture);
|
|
|
|
SystemFontsEnabled = Blurg.EnableSystemFonts();
|
|
}
|
|
|
|
~BlurgEngine()
|
|
{
|
|
Dispose(false, true);
|
|
}
|
|
|
|
public SizeF MeasureString(IFont font, string value)
|
|
{
|
|
return MeasureStringInternal(InternFont(font), value);
|
|
}
|
|
|
|
private SizeF MeasureStringInternal(DbBlurgFont font, string value)
|
|
{
|
|
Vector2 v = Blurg.MeasureString(font.Font, font.Size, value);
|
|
return new SizeF(v.X, v.Y);
|
|
}
|
|
|
|
public IFont LoadFont(Stream stream)
|
|
{
|
|
string path;
|
|
Stream dest;
|
|
for (int i = 0;; i++)
|
|
{
|
|
path = Path.GetTempFileName();
|
|
try
|
|
{
|
|
dest = File.Open(path, FileMode.CreateNew, FileAccess.Write, FileShare.None);
|
|
}
|
|
catch (IOException ex)
|
|
{
|
|
if (i < 3)
|
|
continue;
|
|
else
|
|
throw new Exception("Could not open a temporary file for writing the font.", ex);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
stream.CopyTo(dest);
|
|
dest.Dispose();
|
|
|
|
DbBlurgFont font = (DbBlurgFont)LoadFont(path);
|
|
File.Delete(path);
|
|
return font;
|
|
}
|
|
|
|
public IFont LoadFont(string path)
|
|
{
|
|
BlurgFont? font = Blurg.AddFontFile(path) ?? throw new Exception("Failed to load the font file.");
|
|
return new DbBlurgFont(Blurg, font, 12f);
|
|
}
|
|
|
|
public IFont LoadFont(NamedFont font)
|
|
{
|
|
// Ignore the stretch argument.
|
|
bool italic = font.Slant != FontSlant.Normal;
|
|
BlurgFont? loaded = Blurg.QueryFont(font.Family, new BlurgText.FontWeight((int)font.Weight), italic);
|
|
|
|
if (loaded != null)
|
|
return new DbBlurgFont(Blurg, loaded, 12f);
|
|
else
|
|
throw new Exception("Font not found.");
|
|
}
|
|
|
|
public DbBlurgFont InternFont(IFont font)
|
|
{
|
|
if (font is NamedFont named)
|
|
{
|
|
return (DbBlurgFont)LoadFont(named);
|
|
}
|
|
else if (font is DbBlurgFont dblurg)
|
|
{
|
|
if (dblurg.Owner != Blurg)
|
|
{
|
|
throw new Exception();
|
|
}
|
|
else
|
|
{
|
|
return dblurg;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
throw new Exception("Unsupported font resource.");
|
|
}
|
|
}
|
|
|
|
private void UpdateTexture(IntPtr texture, IntPtr buffer, int x, int y, int width, int height)
|
|
{
|
|
GL.BindTexture(TextureTarget.Texture2d, (int)texture);
|
|
GL.TexSubImage2D(TextureTarget.Texture2d, 0, x, y, width, height, OPENGL.PixelFormat.Rgba, PixelType.UnsignedByte, buffer);
|
|
// GL.TexSubImage2D(TextureTarget.Texture2d, 0, x, y, width, height, OPENGL.PixelFormat.Red, PixelType.Byte, buffer);
|
|
}
|
|
|
|
private IntPtr AllocateTexture(int width, int height)
|
|
{
|
|
int texture = GL.GenTexture();
|
|
|
|
GL.BindTexture(TextureTarget.Texture2d, texture);
|
|
GL.TexImage2D(TextureTarget.Texture2d, 0, InternalFormat.Rgba, width, height, 0, OPENGL.PixelFormat.Rgba, PixelType.UnsignedByte, IntPtr.Zero);
|
|
// GL.TexImage2D(TextureTarget.Texture2d, 0, InternalFormat.R8, width, height, 0, OPENGL.PixelFormat.Red, PixelType.Byte, IntPtr.Zero);
|
|
|
|
GL.TexParameteri(TextureTarget.Texture2d, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
|
|
GL.TexParameteri(TextureTarget.Texture2d, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);
|
|
// GL.TexParameteri(TextureTarget.Texture2d, TextureParameterName.TextureSwizzleR, (int)TextureSwizzle.One);
|
|
// GL.TexParameteri(TextureTarget.Texture2d, TextureParameterName.TextureSwizzleG, (int)TextureSwizzle.One);
|
|
// GL.TexParameteri(TextureTarget.Texture2d, TextureParameterName.TextureSwizzleB, (int)TextureSwizzle.One);
|
|
// GL.TexParameteri(TextureTarget.Texture2d, TextureParameterName.TextureSwizzleA, (int)TextureSwizzle.Red);
|
|
|
|
_textures.Add(texture);
|
|
|
|
return texture;
|
|
}
|
|
|
|
private bool _isDisposed = false;
|
|
|
|
private void Dispose(bool disposing, bool safeExit)
|
|
{
|
|
if (_isDisposed)
|
|
return;
|
|
_isDisposed = true;
|
|
|
|
if (disposing)
|
|
{
|
|
Blurg.Dispose();
|
|
GC.SuppressFinalize(this);
|
|
}
|
|
|
|
if (safeExit)
|
|
{
|
|
foreach (int texture in _textures)
|
|
ContextCollector.Global.DeleteTexture(texture);
|
|
}
|
|
}
|
|
|
|
public void Dispose() => Dispose(true, true);
|
|
|
|
public void Dispose(bool safeExit) => Dispose(true, safeExit);
|
|
|
|
/// <summary>
|
|
/// The global Blurg engine implements the needed methods for command queues to work.
|
|
/// </summary>
|
|
public static BlurgEngine Global { get; } = new BlurgEngine(true);
|
|
|
|
private static void UpdateTextureGlobal(IntPtr userdata, IntPtr buffer, int x, int y, int width, int height)
|
|
{
|
|
// Report the user error.
|
|
Debug.WriteLine("Attempt to create or update a texture from the global BlurgEngine.", "Dashboard/BlurgEngine");
|
|
}
|
|
|
|
private static IntPtr AllocateTextureGlobal(int width, int height)
|
|
{
|
|
Debug.WriteLine("Attempt to create or update a texture from the global BlurgEngine.", "Dashboard/BlurgEngine");
|
|
return IntPtr.Zero;
|
|
}
|
|
}
|
|
}
|