diff --git a/src/Graphics/Font/Font.cs b/src/Graphics/Font/Font.cs index cf4982e..024b3df 100644 --- a/src/Graphics/Font/Font.cs +++ b/src/Graphics/Font/Font.cs @@ -5,29 +5,107 @@ using WellspringCS; namespace MoonWorks.Graphics.Font { - public class Font : IDisposable - { - public IntPtr Handle { get; } + public unsafe class Font : IDisposable + { + public Texture Texture { get; } + + internal IntPtr Handle { get; } + + private byte* StringBytes; + private int StringBytesLength; private bool IsDisposed; - public unsafe Font(string path) - { - var fileStream = new FileStream(path, FileMode.Open, FileAccess.Read); - var fileByteBuffer = NativeMemory.Alloc((nuint) fileStream.Length); - var fileByteSpan = new Span(fileByteBuffer, (int) fileStream.Length); - fileStream.ReadExactly(fileByteSpan); - fileStream.Close(); + 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(); - Handle = Wellspring.Wellspring_CreateFont((IntPtr) fileByteBuffer, (uint) fileByteSpan.Length); + 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(); - NativeMemory.Free(fileByteBuffer); - } + var handle = Wellspring.Wellspring_CreateFont( + (IntPtr) fontFileByteBuffer, + (uint) fontFileByteSpan.Length, + (IntPtr) atlasFileByteBuffer, + (uint) atlasFileByteSpan.Length + ); + + var texture = Texture.FromImageFile(graphicsDevice, commandBuffer, Path.ChangeExtension(fontPath, ".png")); + + NativeMemory.Free(fontFileByteBuffer); + NativeMemory.Free(atlasFileByteBuffer); + + return new Font(handle, texture); + } + + private Font(IntPtr handle, Texture texture) + { + Handle = handle; + Texture = texture; + + StringBytesLength = 32; + StringBytes = (byte*) NativeMemory.Alloc((nuint) StringBytesLength); + } + + public unsafe bool TextBounds( + string text, + float x, + float y, + 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, + x, + y, + (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; } @@ -35,8 +113,8 @@ namespace MoonWorks.Graphics.Font ~Font() { - // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method - Dispose(disposing: false); + // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method + Dispose(disposing: false); } public void Dispose() diff --git a/src/Graphics/Font/MSDF/Decoder.cs b/src/Graphics/Font/MSDF/Decoder.cs deleted file mode 100644 index effae24..0000000 --- a/src/Graphics/Font/MSDF/Decoder.cs +++ /dev/null @@ -1,43 +0,0 @@ -using System.Runtime.CompilerServices; - -namespace MoonWorks.Graphics.Font -{ - /* UTF-8 Decoder */ - - /* Copyright (c) 2008-2009 Bjoern Hoehrmann - * See http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ for details. - */ - - public static class Decoder - { - static byte[] utf8d = new byte[] { - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 00..1f - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 20..3f - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 40..5f - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 60..7f - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, // 80..9f - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, // a0..bf - 8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // c0..df - 0xa,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x4,0x3,0x3, // e0..ef - 0xb,0x6,0x6,0x6,0x5,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8, // f0..ff - 0x0,0x1,0x2,0x3,0x5,0x8,0x7,0x1,0x1,0x1,0x4,0x6,0x1,0x1,0x1,0x1, // s0..s0 - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,1, // s1..s2 - 1,2,1,1,1,1,1,2,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1, // s3..s4 - 1,2,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,3,1,1,1,1,1,1, // s5..s6 - 1,3,1,1,1,1,1,3,1,3,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // s7..s8 - }; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static unsafe uint Decode(uint* state, uint* codep, uint dbyte) { - uint type = utf8d[dbyte]; - - *codep = (uint) ((*state != 0) ? - (dbyte & 0x3fu) | (*codep << 6) : - (0xff >> (int) type) & (dbyte)); - - *state = utf8d[256 + *state*16 + type]; - return *state; - } - - } -} diff --git a/src/Graphics/Font/MSDF/Font.cs b/src/Graphics/Font/MSDF/Font.cs deleted file mode 100644 index c0ea1c8..0000000 --- a/src/Graphics/Font/MSDF/Font.cs +++ /dev/null @@ -1,58 +0,0 @@ -using System; -using System.IO; -using System.Text.Json; - -namespace MoonWorks.Graphics.Font.MSDF; - -public class Font : IDisposable -{ - public Texture Texture { get; } - internal AtlasData AtlasData; - - static JsonSerializerOptions SerializerOptions = new JsonSerializerOptions - { - PropertyNameCaseInsensitive = true, - IncludeFields = true - }; - static AtlasDataContext Context = new AtlasDataContext(SerializerOptions); - - private bool IsDisposed; - - public static Font Load( - GraphicsDevice graphicsDevice, - CommandBuffer commandBuffer, - string jsonPath - ) { - var atlasData = (AtlasData) JsonSerializer.Deserialize(File.ReadAllText(jsonPath), typeof(AtlasData), Context); - var imagePath = Path.ChangeExtension(jsonPath, ".png"); - var texture = Texture.FromImageFile(graphicsDevice, commandBuffer, imagePath); - - return new Font(texture, atlasData); - } - - private Font(Texture texture, AtlasData atlasData) - { - Texture = texture; - AtlasData = atlasData; - } - - protected virtual void Dispose(bool disposing) - { - if (!IsDisposed) - { - if (disposing) - { - Texture.Dispose(); - } - - IsDisposed = true; - } - } - - public void Dispose() - { - // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method - Dispose(disposing: true); - GC.SuppressFinalize(this); - } -} diff --git a/src/Graphics/Font/MSDF/Structs.cs b/src/Graphics/Font/MSDF/Structs.cs deleted file mode 100644 index cedfc41..0000000 --- a/src/Graphics/Font/MSDF/Structs.cs +++ /dev/null @@ -1,85 +0,0 @@ -using System.Text.Json.Serialization; -using MoonWorks.Math.Float; - -namespace MoonWorks.Graphics.Font.MSDF; - -[JsonSerializable(typeof(AtlasData))] -internal partial class AtlasDataContext : JsonSerializerContext -{ -} - -// Reads from an atlas generated by msdf-atlas-gen -public struct AtlasData -{ - public Atlas Atlas; - public Metrics Metrics; - public Glyph[] Glyphs; -} - -public struct Atlas -{ - public FieldType Type; - public int DistanceRange; - public int Size; - public int Width; - public int Height; - public Origin YOrigin; -} - -public struct Metrics -{ - public int EmSize; - public float LineHeight; - public float Ascender; - public float Descender; - public float UnderlineY; - public float UnderlineThickness; -} - -public struct Glyph -{ - public uint Unicode; - public float Advance; - public Bounds PlaneBounds; - public Bounds AtlasBounds; -} - -public struct Bounds -{ - public float Left; - public float Bottom; - public float Right; - public float Top; -} - -public enum FieldType -{ - Hardmask, - Softmask, - SDF, - PSDF, - MSDF, - MTSDF -} - -public enum Origin -{ - Top, - Bottom -} - -public struct FontVertex : IVertexType -{ - public Vector3 Position; - public Vector2 TexCoord; - public Color Color; - - private static readonly VertexElementFormat[] vertexElementFormats = new VertexElementFormat[] - { - VertexElementFormat.Vector3, - VertexElementFormat.Vector2, - VertexElementFormat.Color - }; - - public static VertexElementFormat[] Formats => vertexElementFormats; -} diff --git a/src/Graphics/Font/MSDF/TextBatch.cs b/src/Graphics/Font/MSDF/TextBatch.cs deleted file mode 100644 index 7e4f285..0000000 --- a/src/Graphics/Font/MSDF/TextBatch.cs +++ /dev/null @@ -1,188 +0,0 @@ -using System; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -namespace MoonWorks.Graphics.Font.MSDF; - -public unsafe class TextBatch : IDisposable -{ - public const int MAX_CHARS = 4096; - public const int MAX_VERTICES = MAX_CHARS * 4; - public const int MAX_INDICES = MAX_CHARS * 6; - - public GraphicsDevice GraphicsDevice; - public Font Font; - - public Buffer VertexBuffer; - public Buffer IndexBuffer; - - public byte* VertexData; - public byte* IndexData; - - private int CurrentVertexDataLengthInBytes; - private int CurrentIndexDataLengthInBytes; - - private byte* StringBytes; - private int StringBytesCount = 16; - - private bool IsDisposed; - - public TextBatch(GraphicsDevice graphicsDevice) - { - GraphicsDevice = graphicsDevice; - } - - public void Start() - { - VertexBuffer = Buffer.Create(GraphicsDevice, BufferUsageFlags.Vertex, MAX_VERTICES); - IndexBuffer = Buffer.Create(GraphicsDevice, BufferUsageFlags.Index, MAX_INDICES); - VertexData = (byte*) NativeMemory.Alloc((nuint) (MAX_VERTICES * Unsafe.SizeOf())); - IndexData = (byte*) NativeMemory.Alloc((nuint) (MAX_INDICES * Unsafe.SizeOf())); - StringBytes = (byte*) NativeMemory.Alloc(128); - } - - public void AddText( - string text, - float x, - float y, - float depth, - Color color, - HorizontalAlignment horizontalAlignment = HorizontalAlignment.Left, - VerticalAlignment verticalAlignment = VerticalAlignment.Baseline - ) { - uint decodeState; - uint codepoint; - - var byteCount = System.Text.Encoding.UTF8.GetByteCount(text); - - if (StringBytesCount < byteCount) - { - StringBytes = (byte*) NativeMemory.Realloc(StringBytes, (nuint) byteCount); - StringBytesCount = byteCount; - } - - fixed (char* chars = text) - { - var bytesWritten = System.Text.Encoding.UTF8.GetBytes(chars, text.Length, StringBytes, byteCount); - - y += GetVerticalAlignOffset(verticalAlignment); - - if (horizontalAlignment == HorizontalAlignment.Right) - { - // TODO: check text bounds to adjust alignment - } - - for (var i = 0; i < bytesWritten; i += 1) - { - if (Decoder.Decode(&decodeState, &codepoint, StringBytes[i]) > 0) - { - if (decodeState == 1) - { - // Something went wrong! - return; - } - - continue; - } - - // TODO: we need to convert AtlasData so that codepoints are looked up by key - if (IsWhitespace(codepoint)) - { - x += GetHorizontalAdvance(codepoint); - continue; - } - } - - // TODO: draw the rest of the owl - } - } - - // Call this after you have made all the Draw calls you want. - public void UploadBufferData(CommandBuffer commandBuffer) - { - if (CurrentVertexDataLengthInBytes > 0 && CurrentIndexDataLengthInBytes > 0) - { - commandBuffer.SetBufferData(VertexBuffer, (nint) VertexData, 0, (uint) CurrentVertexDataLengthInBytes); - commandBuffer.SetBufferData(IndexBuffer, (nint) IndexData, 0, (uint) CurrentIndexDataLengthInBytes); - } - } - - private float GetHorizontalAdvance(uint codepoint) - { - Font.AtlasData.Glyphs - } - - private float GetVerticalAlignOffset(VerticalAlignment verticalAlignment) - { - switch (verticalAlignment) - { - case VerticalAlignment.Baseline: - return 0; - - case VerticalAlignment.Top: - return Font.AtlasData.Metrics.Ascender; - - case VerticalAlignment.Middle: - return (Font.AtlasData.Metrics.Ascender + Font.AtlasData.Metrics.Descender) / 2f; - - case VerticalAlignment.Bottom: - return Font.AtlasData.Metrics.Descender; - - default: - return 0; - } - } - - private static bool IsWhitespace(uint codepoint) - { - switch (codepoint) - { - case 0x0020: - case 0x00A0: - case 0x1680: - case 0x202F: - case 0x205F: - case 0x3000: - return true; - - default: - if (codepoint > 0x2000 && codepoint <= 0x200A) - { - return true; - } - - return false; - } - } - - protected virtual void Dispose(bool disposing) - { - if (!IsDisposed) - { - if (disposing) - { - VertexBuffer.Dispose(); - IndexBuffer.Dispose(); - } - - NativeMemory.Free(VertexData); - NativeMemory.Free(IndexData); - NativeMemory.Free(StringBytes); - - IsDisposed = true; - } - } - - ~TextBatch() - { - // 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); - } -} diff --git a/src/Graphics/Font/Packer.cs b/src/Graphics/Font/Packer.cs deleted file mode 100644 index 9fa053c..0000000 --- a/src/Graphics/Font/Packer.cs +++ /dev/null @@ -1,103 +0,0 @@ -using System; -using System.IO; -using System.Runtime.InteropServices; -using WellspringCS; - -namespace MoonWorks.Graphics.Font -{ - public class Packer : IDisposable - { - public IntPtr Handle { get; } - public Texture Texture { get; } - - public Font Font { get; } - - private byte[] StringBytes; - - private bool IsDisposed; - - public unsafe Packer(GraphicsDevice graphicsDevice, Font font, float fontSize, uint textureWidth, uint textureHeight, uint padding = 1) - { - Font = font; - Handle = Wellspring.Wellspring_CreatePacker(Font.Handle, fontSize, textureWidth, textureHeight, 0, padding); - Texture = Texture.CreateTexture2D(graphicsDevice, textureWidth, textureHeight, TextureFormat.R8, TextureUsageFlags.Sampler); - StringBytes = new byte[128]; - } - - public unsafe bool PackFontRanges(params FontRange[] fontRanges) - { - fixed (FontRange *pFontRanges = &fontRanges[0]) - { - var nativeSize = fontRanges.Length * Marshal.SizeOf(); - var result = Wellspring.Wellspring_PackFontRanges(Handle, (IntPtr) pFontRanges, (uint) fontRanges.Length); - return result > 0; - } - } - - public unsafe void SetTextureData(CommandBuffer commandBuffer) - { - var pixelDataPointer = Wellspring.Wellspring_GetPixelDataPointer(Handle); - commandBuffer.SetTextureData(Texture, pixelDataPointer, Texture.Width * Texture.Height); - } - - public unsafe void TextBounds( - string text, - float x, - float y, - HorizontalAlignment horizontalAlignment, - VerticalAlignment verticalAlignment, - out Wellspring.Rectangle rectangle - ) { - var byteCount = System.Text.Encoding.UTF8.GetByteCount(text); - - if (StringBytes.Length < byteCount) - { - System.Array.Resize(ref StringBytes, byteCount); - } - - fixed (char* chars = text) - fixed (byte* bytes = StringBytes) - { - System.Text.Encoding.UTF8.GetBytes(chars, text.Length, bytes, byteCount); - Wellspring.Wellspring_TextBounds( - Handle, - x, - y, - (Wellspring.HorizontalAlignment) horizontalAlignment, - (Wellspring.VerticalAlignment) verticalAlignment, - (IntPtr) bytes, - (uint) byteCount, - out rectangle - ); - } - } - - protected virtual void Dispose(bool disposing) - { - if (!IsDisposed) - { - if (disposing) - { - Texture.Dispose(); - } - - Wellspring.Wellspring_DestroyPacker(Handle); - - IsDisposed = true; - } - } - - ~Packer() - { - // 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); - } - } -} diff --git a/src/Graphics/Font/Structs.cs b/src/Graphics/Font/Structs.cs index 8231039..b5b1e5a 100644 --- a/src/Graphics/Font/Structs.cs +++ b/src/Graphics/Font/Structs.cs @@ -3,15 +3,6 @@ using MoonWorks.Math.Float; namespace MoonWorks.Graphics.Font { - [StructLayout(LayoutKind.Sequential)] - public struct FontRange - { - public uint FirstCodepoint; - public uint NumChars; - public byte OversampleH; - public byte OversampleV; - } - [StructLayout(LayoutKind.Sequential)] public struct Vertex { diff --git a/src/Graphics/Font/TextBatch.cs b/src/Graphics/Font/TextBatch.cs index 119fbde..c043909 100644 --- a/src/Graphics/Font/TextBatch.cs +++ b/src/Graphics/Font/TextBatch.cs @@ -1,35 +1,49 @@ using System; +using System.Runtime.InteropServices; using WellspringCS; namespace MoonWorks.Graphics.Font { - public class TextBatch + public unsafe class TextBatch : IDisposable { + public const int MAX_CHARS = 4096; + public const int MAX_VERTICES = MAX_CHARS * 4; + public const int MAX_INDICES = MAX_CHARS * 6; + private GraphicsDevice GraphicsDevice { get; } public IntPtr Handle { get; } public Buffer VertexBuffer { get; protected set; } = null; public Buffer IndexBuffer { get; protected set; } = null; - public Texture Texture { get; protected set; } public uint PrimitiveCount { get; protected set; } - private byte[] StringBytes; + private Font CurrentFont; + + private byte* StringBytes; + private int StringBytesLength; + + private bool IsDisposed; public TextBatch(GraphicsDevice graphicsDevice) { GraphicsDevice = graphicsDevice; Handle = Wellspring.Wellspring_CreateTextBatch(); - StringBytes = new byte[128]; + + StringBytesLength = 128; + StringBytes = (byte*) NativeMemory.Alloc((nuint) StringBytesLength); + + VertexBuffer = Buffer.Create(GraphicsDevice, BufferUsageFlags.Vertex, MAX_VERTICES); + IndexBuffer = Buffer.Create(GraphicsDevice, BufferUsageFlags.Index, MAX_INDICES); } - public void Start(Packer packer) + public void Start(Font font) { - Wellspring.Wellspring_StartTextBatch(Handle, packer.Handle); - Texture = packer.Texture; + Wellspring.Wellspring_StartTextBatch(Handle, font.Handle); + CurrentFont = font; PrimitiveCount = 0; } - public unsafe void Draw( + public unsafe bool Add( string text, float x, float y, @@ -40,15 +54,14 @@ namespace MoonWorks.Graphics.Font ) { var byteCount = System.Text.Encoding.UTF8.GetByteCount(text); - if (StringBytes.Length < byteCount) + if (StringBytesLength < byteCount) { - System.Array.Resize(ref StringBytes, byteCount); + StringBytes = (byte*) NativeMemory.Realloc(StringBytes, (nuint) byteCount); } fixed (char* chars = text) - fixed (byte* bytes = StringBytes) { - System.Text.Encoding.UTF8.GetBytes(chars, text.Length, bytes, byteCount); + System.Text.Encoding.UTF8.GetBytes(chars, text.Length, StringBytes, byteCount); var result = Wellspring.Wellspring_Draw( Handle, @@ -58,15 +71,18 @@ namespace MoonWorks.Graphics.Font new Wellspring.Color { R = color.R, G = color.G, B = color.B, A = color.A }, (Wellspring.HorizontalAlignment) horizontalAlignment, (Wellspring.VerticalAlignment) verticalAlignment, - (IntPtr) bytes, + (IntPtr) StringBytes, (uint) byteCount ); if (result == 0) { - throw new System.ArgumentException("Could not decode string!"); + Logger.LogWarn("Could not decode string: " + text); + return false; } } + + return true; } // Call this after you have made all the Draw calls you want. @@ -81,26 +97,6 @@ namespace MoonWorks.Graphics.Font out uint indexDataLengthInBytes ); - if (VertexBuffer == null) - { - VertexBuffer = new Buffer(GraphicsDevice, BufferUsageFlags.Vertex, vertexDataLengthInBytes); - } - else if (VertexBuffer.Size < vertexDataLengthInBytes) - { - VertexBuffer.Dispose(); - VertexBuffer = new Buffer(GraphicsDevice, BufferUsageFlags.Vertex, vertexDataLengthInBytes); - } - - if (IndexBuffer == null) - { - IndexBuffer = new Buffer(GraphicsDevice, BufferUsageFlags.Index, indexDataLengthInBytes); - } - else if (IndexBuffer.Size < indexDataLengthInBytes) - { - IndexBuffer.Dispose(); - IndexBuffer = new Buffer(GraphicsDevice, BufferUsageFlags.Index, indexDataLengthInBytes); - } - if (vertexDataLengthInBytes > 0 && indexDataLengthInBytes > 0) { commandBuffer.SetBufferData(VertexBuffer, vertexDataPointer, 0, vertexDataLengthInBytes); @@ -109,5 +105,34 @@ namespace MoonWorks.Graphics.Font PrimitiveCount = vertexCount / 2; // FIXME: is this jank? } + + protected virtual void Dispose(bool disposing) + { + if (!IsDisposed) + { + if (disposing) + { + VertexBuffer.Dispose(); + IndexBuffer.Dispose(); + } + + NativeMemory.Free(StringBytes); + + IsDisposed = true; + } + } + + ~TextBatch() + { + // 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); + } } }