Make SpriteFont.Measure take zero allocations

This commit is contained in:
teinarss
2021-03-29 19:20:07 +02:00
committed by reaperrr
parent a02737107e
commit 3d381e6e32
2 changed files with 61 additions and 13 deletions

View File

@@ -533,6 +533,50 @@ namespace OpenRA
return default(T);
}
public static LineSplitEnumerator SplitLines(this string str, char separator)
{
return new LineSplitEnumerator(str.AsSpan(), separator);
}
}
public ref struct LineSplitEnumerator
{
ReadOnlySpan<char> str;
readonly char separator;
public LineSplitEnumerator(ReadOnlySpan<char> str, char separator)
{
this.str = str;
this.separator = separator;
Current = default;
}
public LineSplitEnumerator GetEnumerator() => this;
public bool MoveNext()
{
var span = str;
// Reach the end of the string
if (span.Length == 0)
return false;
var index = span.IndexOf(separator);
if (index == -1)
{
// The remaining string is an empty string
str = ReadOnlySpan<char>.Empty;
Current = span;
return true;
}
Current = span.Slice(0, index);
str = span.Slice(index + 1);
return true;
}
public ReadOnlySpan<char> Current { get; private set; }
}
public static class Enum<T>

View File

@@ -10,7 +10,6 @@
#endregion
using System;
using System.Linq;
using OpenRA.Primitives;
using OpenRA.Support;
@@ -21,7 +20,6 @@ namespace OpenRA.Graphics
public int TopOffset { get; private set; }
readonly int size;
readonly SheetBuilder builder;
readonly Func<string, float> lineWidth;
readonly IFont font;
readonly Cache<char, GlyphInfo> glyphs;
readonly Cache<(char C, int Radius), Sprite> contrastGlyphs;
@@ -43,10 +41,6 @@ namespace OpenRA.Graphics
contrastGlyphs = new Cache<(char, int), Sprite>(CreateContrastGlyph);
dilationElements = new Cache<int, float[]>(CreateCircularWeightMap);
// PERF: Cache these delegates for Measure calls.
Func<char, float> characterWidth = character => glyphs[character].Advance;
lineWidth = line => line.Sum(characterWidth) / deviceScale;
// Pre-cache small font sizes so glyphs are immediately available when we need them
if (size <= 24)
using (new PerfTimer("Precache {0} {1}px".F(name, size)))
@@ -238,16 +232,26 @@ namespace OpenRA.Graphics
if (string.IsNullOrEmpty(text))
return new int2(0, size);
var lines = text.Split('\n');
return new int2((int)Math.Ceiling(MaxLineWidth(lines, lineWidth)), lines.Length * size);
var lines = text.SplitLines('\n');
var maxWidth = 0f;
var rows = 0;
foreach (var line in lines)
{
rows++;
maxWidth = Math.Max(maxWidth, LineWidth(line));
}
static float MaxLineWidth(string[] lines, Func<string, float> lineWidth)
return new int2((int)Math.Ceiling(maxWidth), rows * size);
}
float LineWidth(ReadOnlySpan<char> line)
{
var maxWidth = 0f;
foreach (var line in lines)
maxWidth = Math.Max(maxWidth, lineWidth(line));
return maxWidth;
var result = 0f;
foreach (var c in line)
result += glyphs[c].Advance;
return result / deviceScale;
}
GlyphInfo CreateGlyph(char c)