Simple font rendering
This commit is contained in:
parent
2dba623005
commit
e550889328
3 changed files with 202 additions and 11 deletions
|
@ -3,10 +3,12 @@
|
|||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp2.1</TargetFramework>
|
||||
<RuntimeIdentifiers>win10-x64;osx-x64;linux-x64</RuntimeIdentifiers>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="OpenTK.NetStandard" Version="1.0.4" />
|
||||
<PackageReference Include="SharpFontCore" Version="0.1.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
using OpenTK.Graphics.OpenGL;
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using Ryujinx.Profiler.UI.SharpFontHelpers;
|
||||
|
||||
namespace Ryujinx
|
||||
{
|
||||
|
@ -9,6 +10,7 @@ namespace Ryujinx
|
|||
{
|
||||
private bool visible = true;
|
||||
public bool visibleChanged;
|
||||
private FontService fontService;
|
||||
|
||||
public ProfileWindow()
|
||||
: base(400, 720)
|
||||
|
@ -34,6 +36,8 @@ namespace Ryujinx
|
|||
protected override void OnLoad(EventArgs e)
|
||||
{
|
||||
GL.ClearColor(Color.MidnightBlue);
|
||||
fontService = new FontService();
|
||||
fontService.InitalizeTextures();
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
@ -97,18 +101,11 @@ namespace Ryujinx
|
|||
return;
|
||||
}
|
||||
|
||||
GL.Clear(ClearBufferMask.ColorBufferBit);
|
||||
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
|
||||
|
||||
GL.Begin(BeginMode.Triangles);
|
||||
|
||||
GL.Color3(Color.MidnightBlue);
|
||||
GL.Vertex2(0.0f, 0.0f);
|
||||
GL.Color3(Color.SpringGreen);
|
||||
GL.Vertex2(50.0f, 100.0f);
|
||||
GL.Color3(Color.Ivory);
|
||||
GL.Vertex2(100.0f, 0.0f);
|
||||
|
||||
GL.End();
|
||||
GL.ClearColor(Color.White);
|
||||
fontService.fontColor = Color.Black;
|
||||
fontService.DrawText("This is a test", 50, 50, 32);
|
||||
|
||||
this.SwapBuffers();
|
||||
}
|
||||
|
|
192
Ryujinx.Profiler/UI/SharpFontHelpers/FontService.cs
Normal file
192
Ryujinx.Profiler/UI/SharpFontHelpers/FontService.cs
Normal file
|
@ -0,0 +1,192 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics.OpenGL;
|
||||
using SharpFont;
|
||||
|
||||
namespace Ryujinx.Profiler.UI.SharpFontHelpers
|
||||
{
|
||||
public class FontService
|
||||
{
|
||||
private struct CharacterInfo
|
||||
{
|
||||
public float left, right, bottom, top;
|
||||
public float height, aspectRatio;
|
||||
public int width;
|
||||
}
|
||||
|
||||
private const int SheetWidth = 256;
|
||||
private const int SheetHeight = 256;
|
||||
private int characterTextureSheet;
|
||||
private CharacterInfo[] characters;
|
||||
|
||||
public float characterSpacing = 1;
|
||||
public Color fontColor = Color.Black;
|
||||
|
||||
public void InitalizeTextures()
|
||||
{
|
||||
// Create and init some vars
|
||||
uint[] rawCharacterSheet = new uint[SheetWidth * SheetHeight];
|
||||
int x, y, lineOffset, maxHeight;
|
||||
x = y = lineOffset = maxHeight = 0;
|
||||
characters = new CharacterInfo[94];
|
||||
|
||||
// Get font
|
||||
var font = new FontFace(File.OpenRead(Path.Combine(Environment.GetFolderPath(
|
||||
Environment.SpecialFolder.ApplicationData), @"RyuFs\system\fonts\FontStandard.ttf")));
|
||||
|
||||
// Update raw data for each character
|
||||
for (int i = 0; i < 94; i++)
|
||||
{
|
||||
var surface = RenderSurface((char)(i + 33), font);
|
||||
|
||||
characters[i] = UpdateTexture(surface, ref rawCharacterSheet, ref x, ref y, ref lineOffset);
|
||||
|
||||
if (maxHeight < characters[i].height)
|
||||
maxHeight = (int)characters[i].height;
|
||||
}
|
||||
|
||||
// Fix height for characters shorter than line height
|
||||
for (int i = 0; i < 94; i++)
|
||||
{
|
||||
characters[i].height /= maxHeight;
|
||||
characters[i].aspectRatio = (float)characters[i].width / maxHeight;
|
||||
}
|
||||
|
||||
// Convert raw data into texture
|
||||
characterTextureSheet = GL.GenTexture();
|
||||
GL.BindTexture(TextureTarget.Texture2D, characterTextureSheet);
|
||||
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)TextureWrapMode.Clamp);
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.Clamp);
|
||||
|
||||
GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, SheetWidth, SheetHeight, 0, PixelFormat.Rgba, PixelType.UnsignedInt8888, rawCharacterSheet);
|
||||
|
||||
GL.BindTexture(TextureTarget.Texture2D, 0);
|
||||
}
|
||||
|
||||
public void DrawText(string text, float x, float y, float height)
|
||||
{
|
||||
// Use font map texture
|
||||
GL.BindTexture(TextureTarget.Texture2D, characterTextureSheet);
|
||||
|
||||
// Enable blending and textures
|
||||
GL.Enable(EnableCap.Texture2D);
|
||||
GL.Enable(EnableCap.Blend);
|
||||
GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha);
|
||||
|
||||
// Draw all characters
|
||||
GL.Begin(PrimitiveType.Triangles);
|
||||
GL.Color4(fontColor);
|
||||
|
||||
for (int i = 0; i < text.Length; i++)
|
||||
{
|
||||
if (text[i] == ' ')
|
||||
{
|
||||
x += height / 4;
|
||||
continue;
|
||||
}
|
||||
|
||||
CharacterInfo charInfo = characters[text[i] - 33];
|
||||
float right = x + (charInfo.aspectRatio * height);
|
||||
DrawChar(charInfo, x, right, y + height * charInfo.height, y);
|
||||
x = right + characterSpacing;
|
||||
}
|
||||
|
||||
GL.End();
|
||||
|
||||
// Cleanup for caller
|
||||
GL.BindTexture(TextureTarget.Texture2D, 0);
|
||||
GL.Disable(EnableCap.Texture2D);
|
||||
GL.Disable(EnableCap.Blend);
|
||||
}
|
||||
|
||||
private void DrawChar(CharacterInfo charInfo, float left, float right, float top, float bottom)
|
||||
{
|
||||
GL.TexCoord2(charInfo.left, charInfo.bottom); GL.Vertex2(left, bottom);
|
||||
GL.TexCoord2(charInfo.left, charInfo.top); GL.Vertex2(left, top);
|
||||
GL.TexCoord2(charInfo.right, charInfo.top); GL.Vertex2(right, top);
|
||||
|
||||
GL.TexCoord2(charInfo.right, charInfo.top); GL.Vertex2(right, top);
|
||||
GL.TexCoord2(charInfo.right, charInfo.bottom); GL.Vertex2(right, bottom);
|
||||
GL.TexCoord2(charInfo.left, charInfo.bottom); GL.Vertex2(left, bottom);
|
||||
}
|
||||
|
||||
public unsafe Surface RenderSurface(char c, FontFace font)
|
||||
{
|
||||
var glyph = font.GetGlyph(c, 32);
|
||||
var surface = new Surface
|
||||
{
|
||||
Bits = Marshal.AllocHGlobal(glyph.RenderWidth * glyph.RenderHeight),
|
||||
Width = glyph.RenderWidth,
|
||||
Height = glyph.RenderHeight,
|
||||
Pitch = glyph.RenderWidth
|
||||
};
|
||||
|
||||
var stuff = (byte*)surface.Bits;
|
||||
for (int i = 0; i < surface.Width * surface.Height; i++)
|
||||
*stuff++ = 0;
|
||||
|
||||
glyph.RenderTo(surface);
|
||||
|
||||
return surface;
|
||||
}
|
||||
|
||||
private CharacterInfo UpdateTexture(Surface surface, ref uint[] rawCharMap, ref int posX, ref int posY, ref int lineOffset)
|
||||
{
|
||||
int width = surface.Width;
|
||||
int height = surface.Height;
|
||||
int len = width * height;
|
||||
byte[] data = new byte[len];
|
||||
|
||||
// Get character bitmap
|
||||
Marshal.Copy(surface.Bits, data, 0, len);
|
||||
|
||||
// Find a slot
|
||||
if (posX + width > SheetWidth)
|
||||
{
|
||||
posX = 0;
|
||||
posY += lineOffset;
|
||||
lineOffset = 0;
|
||||
}
|
||||
|
||||
// Update lineoffset
|
||||
if (lineOffset < height)
|
||||
{
|
||||
lineOffset = height + 1;
|
||||
}
|
||||
|
||||
// Copy char to sheet
|
||||
for (int y = 0; y < height; y++)
|
||||
{
|
||||
int destOffset = (y + posY) * SheetWidth + posX;
|
||||
int sourceOffset = y * width;
|
||||
for (int x = 0; x < width; x++)
|
||||
{
|
||||
rawCharMap[destOffset + x] = (uint)((0xFFFFFF << 8) | data[sourceOffset + x]);
|
||||
}
|
||||
}
|
||||
|
||||
// Generate character info
|
||||
CharacterInfo charInfo = new CharacterInfo()
|
||||
{
|
||||
left = (float)posX / SheetWidth,
|
||||
right = (float)(posX + width) / SheetWidth,
|
||||
top = (float)(posY - 1) / SheetHeight,
|
||||
bottom = (float)(posY + height) / SheetHeight,
|
||||
width = width,
|
||||
height = height,
|
||||
};
|
||||
|
||||
// Update x
|
||||
posX += width + 1;
|
||||
|
||||
// Give the memory back
|
||||
Marshal.FreeHGlobal(surface.Bits);
|
||||
return charInfo;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue