diff --git a/MLEM.Extended/Font/GenericStashFont.cs b/MLEM.Extended/Font/GenericStashFont.cs index b84e5e3..0d2988b 100644 --- a/MLEM.Extended/Font/GenericStashFont.cs +++ b/MLEM.Extended/Font/GenericStashFont.cs @@ -33,7 +33,7 @@ namespace MLEM.Extended.Font { /// protected override float MeasureCharacter(int codePoint) { - return this.Font.MeasureString(char.ConvertFromUtf32(codePoint)).X; + return this.Font.MeasureString(this.ConvertCachedUtf32(codePoint)).X; } /// diff --git a/MLEM/Font/GenericFont.cs b/MLEM/Font/GenericFont.cs index 626d2d6..5eaf081 100644 --- a/MLEM/Font/GenericFont.cs +++ b/MLEM/Font/GenericFont.cs @@ -48,6 +48,8 @@ namespace MLEM.Font { /// public abstract float LineHeight { get; } + private readonly Dictionary codePointCache = new Dictionary(); + /// /// Measures the width of the given code point with the default scale for use in . /// Note that this method does not support , and for most generic fonts, which is why should be used even for single characters. @@ -173,6 +175,19 @@ namespace MLEM.Font { return this.SplitStringSeparate(new CodePointSource(text), width, scale, null); } + /// + /// Converts the given UTF-32 into a string using , but caches the result in a cache to avoid allocating excess memory. + /// + /// The UTF-32 code point to convert. + /// The string representation of the code point. + public string ConvertCachedUtf32(int codePoint) { + if (!this.codePointCache.TryGetValue(codePoint, out var ret)) { + ret = char.ConvertFromUtf32(codePoint); + this.codePointCache.Add(codePoint, ret); + } + return ret; + } + internal Vector2 MeasureString(CodePointSource text, bool ignoreTrailingSpaces, Func fontFunction) { var size = Vector2.Zero; if (text.Length <= 0) @@ -225,9 +240,9 @@ namespace MLEM.Font { var innerIndex = fromBack ? text.Length - 1 - index : index; var (codePoint, length) = text.GetCodePoint(innerIndex, fromBack); if (fromBack) { - total.Insert(0, char.ConvertFromUtf32(codePoint)); + total.Insert(0, this.ConvertCachedUtf32(codePoint)); } else { - total.Append(char.ConvertFromUtf32(codePoint)); + total.Append(this.ConvertCachedUtf32(codePoint)); } if (this.MeasureString(new CodePointSource(total + ellipsis), false, fontFunction).X * scale >= width) { @@ -258,7 +273,7 @@ namespace MLEM.Font { currWidth = 0; } else { var font = fontFunction?.Invoke(index) ?? this; - var character = char.ConvertFromUtf32(codePoint); + var character = this.ConvertCachedUtf32(codePoint); var charWidth = font.MeasureString(character).X * scale; if (codePoint == ' ' || codePoint == GenericFont.Emsp || codePoint == GenericFont.Zwsp) { // remember the location of this (breaking!) space @@ -334,7 +349,7 @@ namespace MLEM.Font { offset.X = 0; offset.Y += this.LineHeight; } else { - var character = char.ConvertFromUtf32(codePoint); + var character = this.ConvertCachedUtf32(codePoint); var charSize = this.MeasureString(character); var charPos = offset; diff --git a/MLEM/Font/GenericSpriteFont.cs b/MLEM/Font/GenericSpriteFont.cs index 7d50f7e..d038f4c 100644 --- a/MLEM/Font/GenericSpriteFont.cs +++ b/MLEM/Font/GenericSpriteFont.cs @@ -35,7 +35,7 @@ namespace MLEM.Font { /// protected override float MeasureCharacter(int codePoint) { - return this.Font.MeasureString(char.ConvertFromUtf32(codePoint)).X; + return this.Font.MeasureString(this.ConvertCachedUtf32(codePoint)).X; } /// diff --git a/MLEM/Formatting/TokenizedString.cs b/MLEM/Formatting/TokenizedString.cs index c4b1a4e..918a59d 100644 --- a/MLEM/Formatting/TokenizedString.cs +++ b/MLEM/Formatting/TokenizedString.cs @@ -164,7 +164,7 @@ namespace MLEM.Formatting { var line = new CodePointSource(token.SplitDisplayString[l]); while (charIndex < line.Length) { var (codePoint, length) = line.GetCodePoint(charIndex); - var character = char.ConvertFromUtf32(codePoint); + var character = drawFont.ConvertCachedUtf32(codePoint); if (indexInToken == 0) token.DrawSelf(time, batch, pos + innerOffset, drawFont, color, scale, depth);