MoonWorks/src/Graphics/Font/TextBatch.cs

139 lines
3.4 KiB
C#

using System;
using System.Runtime.InteropServices;
using WellspringCS;
namespace MoonWorks.Graphics.Font
{
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 uint PrimitiveCount { get; protected set; }
private Font CurrentFont;
private byte* StringBytes;
private int StringBytesLength;
private bool IsDisposed;
public TextBatch(GraphicsDevice graphicsDevice)
{
GraphicsDevice = graphicsDevice;
Handle = Wellspring.Wellspring_CreateTextBatch();
StringBytesLength = 128;
StringBytes = (byte*) NativeMemory.Alloc((nuint) StringBytesLength);
VertexBuffer = Buffer.Create<Vertex>(GraphicsDevice, BufferUsageFlags.Vertex, MAX_VERTICES);
IndexBuffer = Buffer.Create<uint>(GraphicsDevice, BufferUsageFlags.Index, MAX_INDICES);
}
public void Start(Font font)
{
Wellspring.Wellspring_StartTextBatch(Handle, font.Handle);
CurrentFont = font;
PrimitiveCount = 0;
}
public unsafe bool Add(
string text,
float x,
float y,
float depth,
Color color,
HorizontalAlignment horizontalAlignment = HorizontalAlignment.Left,
VerticalAlignment verticalAlignment = VerticalAlignment.Baseline
) {
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_Draw(
Handle,
x,
y,
depth,
new Wellspring.Color { R = color.R, G = color.G, B = color.B, A = color.A },
(Wellspring.HorizontalAlignment) horizontalAlignment,
(Wellspring.VerticalAlignment) verticalAlignment,
(IntPtr) StringBytes,
(uint) byteCount
);
if (result == 0)
{
Logger.LogWarn("Could not decode string: " + text);
return false;
}
}
return true;
}
// Call this after you have made all the Draw calls you want.
public unsafe void UploadBufferData(CommandBuffer commandBuffer)
{
Wellspring.Wellspring_GetBufferData(
Handle,
out uint vertexCount,
out IntPtr vertexDataPointer,
out uint vertexDataLengthInBytes,
out IntPtr indexDataPointer,
out uint indexDataLengthInBytes
);
if (vertexDataLengthInBytes > 0 && indexDataLengthInBytes > 0)
{
commandBuffer.SetBufferData(VertexBuffer, vertexDataPointer, 0, vertexDataLengthInBytes);
commandBuffer.SetBufferData(IndexBuffer, indexDataPointer, 0, indexDataLengthInBytes);
}
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);
}
}
}