-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathFontsTextRenderer.cs
103 lines (90 loc) · 3.85 KB
/
FontsTextRenderer.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
using System;
using System.Collections.Generic;
using System.Linq;
using OpenWheels.Fonts;
using SixLabors.Fonts;
namespace OpenWheels.Rendering
{
/// <summary>
/// A font renderer for OpenWheels using SixLabors.Fonts for layout.
/// </summary>
public class FontsTextRenderer : IBitmapFontRenderer
{
/// <summary>
/// Create a new FontsTextRenderer.
/// </summary>
public FontsTextRenderer()
{
}
/// <inheritdoc/>
public RectangleF RenderText(Batcher batcher, TextureFont textureFont, ReadOnlySpan<char> text, float scale, in TextLayoutOptions tlo, Color color)
{
if (textureFont == null)
throw new ArgumentNullException(nameof(textureFont));
var slFont = textureFont.Font;
// TODO other dpi support
var dpi = 72 * scale;
// TODO there is no setter for Font on RendererOptions, once there is we can cache an instance
var ro = new RendererOptions(slFont, dpi, dpi, tlo.Position);
ro.HorizontalAlignment = ToHorizontalAlignment(tlo.HorizontalAlignment);
ro.VerticalAlignment = ToVerticalAlignment(tlo.VerticalAlignment);
ro.WrappingWidth = tlo.WrappingWidth;
ro.TabWidth = tlo.TabWidth;
// TODO this generates garbage; should push for an overload to use an existing collection
TextMeasurer.TryMeasureCharacterBounds(text, ro, out var gms);
if (gms.Length == 0)
return default;
var firstBounds = gms[0].Bounds;
var l = firstBounds.Left;
var t = firstBounds.Top;
var r = firstBounds.Right;
var b = firstBounds.Bottom;
foreach (var gm in gms)
{
// We need to ceil the size because the UV coordinates are computed from rounded pixel coordinates.
// Not sure if this is optimal when scaling is used.
var rect = new RectangleF(gm.Bounds.X, gm.Bounds.Y, (int) Math.Ceiling(gm.Bounds.Width), (int) Math.Ceiling(gm.Bounds.Height));
var gd = textureFont.GetGlyphData(gm.Codepoint);
batcher.SetUvSprite(textureFont.Texture, gd.Bounds);
batcher.FillRect(rect, color);
if (gm.Bounds.Left < l)
l = gm.Bounds.Left;
if (gm.Bounds.Top < t)
t = gm.Bounds.Top;
if (gm.Bounds.Right > r)
r = gm.Bounds.Right;
if (gm.Bounds.Bottom > b)
b = gm.Bounds.Bottom;
}
return RectangleF.FromExtremes(l, t, b, r);
}
private HorizontalAlignment ToHorizontalAlignment(TextAlignment horizontalAlignment)
{
switch (horizontalAlignment)
{
case TextAlignment.Start:
return HorizontalAlignment.Left;
case TextAlignment.Center:
return HorizontalAlignment.Center;
case TextAlignment.End:
return HorizontalAlignment.Right;
default:
throw new ArgumentOutOfRangeException();
}
}
private VerticalAlignment ToVerticalAlignment(TextAlignment verticalAlignment)
{
switch (verticalAlignment)
{
case TextAlignment.Start:
return VerticalAlignment.Top;
case TextAlignment.Center:
return VerticalAlignment.Center;
case TextAlignment.End:
return VerticalAlignment.Bottom;
default:
throw new ArgumentOutOfRangeException();
}
}
}
}