forked from MoonsideGames/MoonWorks
Font Rendering (#18)
Adds a font rendering system based on Wellspring. Reviewed-on: MoonsideGames/MoonWorks#18main
parent
72c9dd4bda
commit
61a6d0bdc0
|
@ -7,3 +7,6 @@
|
|||
[submodule "lib/RefreshCS"]
|
||||
path = lib/RefreshCS
|
||||
url = https://gitea.moonside.games/MoonsideGames/RefreshCS.git
|
||||
[submodule "lib/WellspringCS"]
|
||||
path = lib/WellspringCS
|
||||
url = https://gitea.moonside.games/MoonsideGames/WellspringCS.git
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
<ProjectReference Include=".\lib\SDL2-CS\SDL2-CS.Core.csproj" />
|
||||
<ProjectReference Include=".\lib\RefreshCS\RefreshCS.csproj" />
|
||||
<ProjectReference Include=".\lib\FAudio\csharp\FAudio-CS.Core.csproj" />
|
||||
<ProjectReference Include=".\lib\WellspringCS\WellspringCS.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
@ -11,4 +11,8 @@
|
|||
<dllmap dll="FAudio" os="windows" target="FAudio.dll"/>
|
||||
<dllmap dll="FAudio" os="osx" target="libFAudio.0.dylib"/>
|
||||
<dllmap dll="FAudio" os="linux,freebsd,netbsd" target="libFAudio.so.0"/>
|
||||
|
||||
<dllmap dll="Wellspring" os="windows" target="Wellspring.dll"/>
|
||||
<dllmap dll="Wellspring" os="osx" target="libWellspring.0.dylib"/>
|
||||
<dllmap dll="Wellspring" os="linux,freebsd,netbsd" target="libWellspring.so.0"/>
|
||||
</configuration>
|
||||
|
|
|
@ -14,6 +14,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FAudio-CS.Core", "lib\FAudi
|
|||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RefreshCS", "lib\RefreshCS\RefreshCS.csproj", "{AD7C94E4-0AFA-44CA-889C-110142369893}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "lib", "lib", "{69D3788D-6C57-44F7-A912-B201AE6D7C04}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WellspringCS", "lib\WellspringCS\WellspringCS.csproj", "{0DD7B866-773C-4A86-8580-F436DAA28989}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
|
@ -36,6 +40,10 @@ Global
|
|||
{AD7C94E4-0AFA-44CA-889C-110142369893}.Debug|x64.Build.0 = Debug|x64
|
||||
{AD7C94E4-0AFA-44CA-889C-110142369893}.Release|x64.ActiveCfg = Release|x64
|
||||
{AD7C94E4-0AFA-44CA-889C-110142369893}.Release|x64.Build.0 = Release|x64
|
||||
{0DD7B866-773C-4A86-8580-F436DAA28989}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{0DD7B866-773C-4A86-8580-F436DAA28989}.Debug|x64.Build.0 = Debug|x64
|
||||
{0DD7B866-773C-4A86-8580-F436DAA28989}.Release|x64.ActiveCfg = Release|x64
|
||||
{0DD7B866-773C-4A86-8580-F436DAA28989}.Release|x64.Build.0 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
@ -43,4 +51,7 @@ Global
|
|||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {C3D68FAA-3165-43C7-95B3-D845F0DAA918}
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{0DD7B866-773C-4A86-8580-F436DAA28989} = {69D3788D-6C57-44F7-A912-B201AE6D7C04}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 4b21707900c6d75184f0d5373a0676fe31da956b
|
|
@ -21,6 +21,8 @@ namespace MoonWorks.Graphics
|
|||
Handle = handle;
|
||||
}
|
||||
|
||||
// FIXME: we can probably use the NativeMemory functions to not have to generate arrays here
|
||||
|
||||
/// <summary>
|
||||
/// Begins a render pass.
|
||||
/// All render state, resource binding, and draw commands must be made within a render pass.
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
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; }
|
||||
|
||||
private bool IsDisposed;
|
||||
|
||||
public unsafe Packer(GraphicsDevice graphicsDevice, string path, uint textureWidth, uint textureHeight, uint padding = 1)
|
||||
{
|
||||
var bytes = File.ReadAllBytes(path);
|
||||
fixed (byte* pByte = &bytes[0])
|
||||
{
|
||||
Handle = Wellspring.Wellspring_CreatePacker((IntPtr) pByte, (uint) bytes.Length, textureWidth, textureHeight, 0, padding);
|
||||
}
|
||||
|
||||
Texture = Texture.CreateTexture2D(graphicsDevice, textureWidth, textureHeight, TextureFormat.R8, TextureUsageFlags.Sampler);
|
||||
}
|
||||
|
||||
public unsafe bool PackFontRanges(params FontRange[] fontRanges)
|
||||
{
|
||||
fixed (FontRange *pFontRanges = &fontRanges[0])
|
||||
{
|
||||
var nativeSize = fontRanges.Length * Marshal.SizeOf<Wellspring.FontRange>();
|
||||
void* fontRangeMemory = NativeMemory.Alloc((nuint) fontRanges.Length, (nuint) Marshal.SizeOf<Wellspring.FontRange>());
|
||||
System.Buffer.MemoryCopy(pFontRanges, fontRangeMemory, nativeSize, nativeSize);
|
||||
|
||||
var result = Wellspring.Wellspring_PackFontRanges(Handle, (IntPtr) fontRangeMemory, (uint) fontRanges.Length);
|
||||
|
||||
NativeMemory.Free(fontRangeMemory);
|
||||
|
||||
return result > 0;
|
||||
}
|
||||
}
|
||||
|
||||
public unsafe void SetTextureData(CommandBuffer commandBuffer)
|
||||
{
|
||||
var pixelDataPointer = Wellspring.Wellspring_GetPixelDataPointer(Handle);
|
||||
commandBuffer.SetTextureData(Texture, pixelDataPointer, Texture.Width * Texture.Height);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
using System.Runtime.InteropServices;
|
||||
using MoonWorks.Math;
|
||||
|
||||
namespace MoonWorks.Graphics.Font
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct FontRange
|
||||
{
|
||||
public uint FontSize;
|
||||
public uint FirstCodepoint;
|
||||
public uint NumChars;
|
||||
public byte OversampleH;
|
||||
public byte OversampleV;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct Vertex
|
||||
{
|
||||
public Vector3 Position;
|
||||
public Vector2 TexCoord;
|
||||
public Color Color;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
using System;
|
||||
using WellspringCS;
|
||||
|
||||
namespace MoonWorks.Graphics.Font
|
||||
{
|
||||
public class TextBatch
|
||||
{
|
||||
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; }
|
||||
|
||||
public TextBatch(GraphicsDevice graphicsDevice)
|
||||
{
|
||||
GraphicsDevice = graphicsDevice;
|
||||
Handle = Wellspring.Wellspring_CreateTextBatch();
|
||||
}
|
||||
|
||||
public void Start(Packer packer)
|
||||
{
|
||||
Wellspring.Wellspring_StartTextBatch(Handle, packer.Handle);
|
||||
Texture = packer.Texture;
|
||||
PrimitiveCount = 0;
|
||||
}
|
||||
|
||||
public unsafe void Draw(float x, float y, float depth, Color color, string text)
|
||||
{
|
||||
fixed (char* chars = text)
|
||||
{
|
||||
var byteCount = System.Text.Encoding.UTF8.GetByteCount(text);
|
||||
var bytes = stackalloc byte[byteCount];
|
||||
System.Text.Encoding.UTF8.GetBytes(chars, text.Length, bytes, 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 },
|
||||
(IntPtr) bytes,
|
||||
(uint) byteCount
|
||||
);
|
||||
|
||||
if (result == 0)
|
||||
{
|
||||
throw new System.ArgumentException("Could not decode string!");
|
||||
}
|
||||
|
||||
PrimitiveCount += (uint) (text.Length * 2);
|
||||
}
|
||||
}
|
||||
|
||||
// Call this after you have made all the Draw calls you want.
|
||||
public unsafe void UploadBufferData(CommandBuffer commandBuffer)
|
||||
{
|
||||
Wellspring.Wellspring_GetBufferData(
|
||||
Handle,
|
||||
out IntPtr vertexDataPointer,
|
||||
out uint vertexDataLengthInBytes,
|
||||
out IntPtr indexDataPointer,
|
||||
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);
|
||||
}
|
||||
|
||||
commandBuffer.SetBufferData(VertexBuffer, vertexDataPointer, 0, vertexDataLengthInBytes);
|
||||
commandBuffer.SetBufferData(IndexBuffer, indexDataPointer, 0, indexDataLengthInBytes);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -195,6 +195,7 @@ namespace MoonWorks
|
|||
NativeLibrary.SetDllImportResolver(typeof(SDL2.SDL).Assembly, MapAndLoad);
|
||||
NativeLibrary.SetDllImportResolver(typeof(RefreshCS.Refresh).Assembly, MapAndLoad);
|
||||
NativeLibrary.SetDllImportResolver(typeof(FAudio).Assembly, MapAndLoad);
|
||||
NativeLibrary.SetDllImportResolver(typeof(WellspringCS.Wellspring).Assembly, MapAndLoad);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
|
Loading…
Reference in New Issue