using System; using System.IO; using System.Runtime.InteropServices; using WellspringCS; namespace MoonWorks.Graphics.Font { public unsafe class Font : IDisposable { public Texture Texture { get; } public float PixelsPerEm { get; } internal IntPtr Handle { get; } private byte* StringBytes; private int StringBytesLength; private bool IsDisposed; public unsafe static Font Load( GraphicsDevice graphicsDevice, CommandBuffer commandBuffer, string fontPath ) { var fontFileStream = new FileStream(fontPath, FileMode.Open, FileAccess.Read); var fontFileByteBuffer = NativeMemory.Alloc((nuint) fontFileStream.Length); var fontFileByteSpan = new Span(fontFileByteBuffer, (int) fontFileStream.Length); fontFileStream.ReadExactly(fontFileByteSpan); fontFileStream.Close(); var atlasFileStream = new FileStream(Path.ChangeExtension(fontPath, ".json"), FileMode.Open, FileAccess.Read); var atlasFileByteBuffer = NativeMemory.Alloc((nuint) atlasFileStream.Length); var atlasFileByteSpan = new Span(atlasFileByteBuffer, (int) atlasFileStream.Length); atlasFileStream.ReadExactly(atlasFileByteSpan); atlasFileStream.Close(); var handle = Wellspring.Wellspring_CreateFont( (IntPtr) fontFileByteBuffer, (uint) fontFileByteSpan.Length, (IntPtr) atlasFileByteBuffer, (uint) atlasFileByteSpan.Length, out float pixelsPerEm ); var texture = Texture.FromImageFile(graphicsDevice, commandBuffer, Path.ChangeExtension(fontPath, ".png")); NativeMemory.Free(fontFileByteBuffer); NativeMemory.Free(atlasFileByteBuffer); return new Font(handle, texture, pixelsPerEm); } private Font(IntPtr handle, Texture texture, float pixelsPerEm) { Handle = handle; Texture = texture; PixelsPerEm = pixelsPerEm; StringBytesLength = 32; StringBytes = (byte*) NativeMemory.Alloc((nuint) StringBytesLength); } public unsafe bool TextBounds( string text, int pixelSize, HorizontalAlignment horizontalAlignment, VerticalAlignment verticalAlignment, out Wellspring.Rectangle rectangle ) { var byteCount = System.Text.Encoding.UTF8.GetByteCount(text); if (StringBytesLength < byteCount) { StringBytes = (byte*) NativeMemory.Realloc(StringBytes, (nuint) byteCount); } fixed (char* chars = text) { System.Text.Encoding.UTF8.GetBytes(chars, text.Length, StringBytes, byteCount); var result = Wellspring.Wellspring_TextBounds( Handle, pixelSize, (Wellspring.HorizontalAlignment) horizontalAlignment, (Wellspring.VerticalAlignment) verticalAlignment, (IntPtr) StringBytes, (uint) byteCount, out rectangle ); if (result == 0) { Logger.LogWarn("Could not decode string: " + text); return false; } } return true; } protected virtual void Dispose(bool disposing) { if (!IsDisposed) { if (disposing) { Texture.Dispose(); } Wellspring.Wellspring_DestroyFont(Handle); IsDisposed = true; } } ~Font() { // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method Dispose(disposing: false); } public void Dispose() { // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method Dispose(disposing: true); GC.SuppressFinalize(this); } } }