Skip to content

Commit

Permalink
Allow SpriteFont to optionally not premultiply the alpha channel
Browse files Browse the repository at this point in the history
  • Loading branch information
NoelFB committed Jun 5, 2024
1 parent 0bfcd24 commit 88d3754
Showing 1 changed file with 31 additions and 27 deletions.
58 changes: 31 additions & 27 deletions Framework/Graphics/SpriteFont.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Numerics;

namespace Foster.Framework;
Expand Down Expand Up @@ -27,7 +26,7 @@ bool Exists
/// <summary>
/// Set of ASCII character unicode values
/// </summary>
public static readonly int[] Ascii;
public static readonly int[] Ascii = Enumerable.Range(32, 128 - 32).ToArray();

/// <summary>
/// The Font being used by the SpriteFont.
Expand All @@ -46,13 +45,6 @@ bool Exists
/// </summary>
public readonly float Size;

/// <summary>
/// If the SpriteFont is allowed to dynamically blit Characters as they are
/// requested. If this is false, no new characters that have not already been
/// rendered will be created.
/// </summary>
public bool DynamicBlittingEnabled = true;

/// <summary>
/// Font Ascent
/// </summary>
Expand All @@ -78,41 +70,49 @@ bool Exists
/// </summary>
public float LineHeight => Ascent - Descent + LineGap;

/// <summary>
/// If the SpriteFont is allowed to dynamically blit Characters as they are
/// requested. If this is false, no new characters that have not already been
/// rendered will be created.
/// </summary>
public bool DynamicBlittingEnabled = true;

/// <summary>
/// If the generated character images should premultiply their alpha.
/// This should be true if you render the SpriteFont with the default
/// Premultiply BlendMode.
/// Note that this property does not modify already-created characters.
/// </summary>
public bool PremultiplyAlpha = true;

private readonly float fontScale = 1.0f;
private readonly Dictionary<int, Character> characters = [];
private readonly Dictionary<KerningPair, float> kerning = [];
private readonly List<Page> texturePages = [];
private Color[] buffer = [];

static SpriteFont()
{
var ascii = new List<int>();
for (int i = 32; i < 128; i ++)
ascii.Add(i);
Ascii = [.. ascii];
}

public SpriteFont(Font font, float size, ReadOnlySpan<int> prebakedCodepoints = default)
public SpriteFont(Font font, float size, ReadOnlySpan<int> prebakedCodepoints = default, bool premultiplyAlpha = true)
{
Font = font;
Size = size;
fontScale = font.GetScale(size);
Ascent = font.Ascent * fontScale;
Descent = font.Descent * fontScale;
LineGap = font.LineGap * fontScale;
PremultiplyAlpha = premultiplyAlpha;

if (prebakedCodepoints.Length > 0)
PrepareCharacters(prebakedCodepoints, true);
}

public SpriteFont(string path, float size, ReadOnlySpan<int> prebakedCodepoints = default)
: this(new Font(path), size, prebakedCodepoints)
public SpriteFont(string path, float size, ReadOnlySpan<int> prebakedCodepoints = default, bool premultiplyAlpha = true)
: this(new Font(path), size, prebakedCodepoints, premultiplyAlpha)
{

}

public SpriteFont(Stream stream, float size, ReadOnlySpan<int> prebakedCodepoints = default)
: this(new Font(stream), size, prebakedCodepoints)
public SpriteFont(Stream stream, float size, ReadOnlySpan<int> prebakedCodepoints = default, bool premultiplyAlpha = true)
: this(new Font(stream), size, prebakedCodepoints, premultiplyAlpha)
{

}
Expand Down Expand Up @@ -377,7 +377,7 @@ private Character PrepareCharacter(int codepoint, bool immediate)
{
if (immediate)
{
if (TryBlitCharacter(Font, metrics, ref buffer) &&
if (TryBlitCharacter(Font, metrics, ref buffer, PremultiplyAlpha) &&
TryPackCharacter(buffer, metrics.Width, metrics.Height, out var tex))
subtex = tex;
}
Expand All @@ -399,16 +399,20 @@ private Character PrepareCharacter(int codepoint, bool immediate)
);
}

private static bool TryBlitCharacter(Font font, in Font.Character ch, ref Color[] buffer)
private static bool TryBlitCharacter(Font font, in Font.Character ch, ref Color[] buffer, bool premultiply)
{
var length = ch.Width * ch.Height;
if (buffer.Length <= length)
Array.Resize(ref buffer, length);

if (font.GetPixels(ch, buffer))
{
for (int i = 0; i < length; i ++)
buffer[i] = buffer[i].Premultiply();
if (premultiply)
{
for (int i = 0; i < length; i ++)
buffer[i] = buffer[i].Premultiply();
}

return true;
}

Expand Down Expand Up @@ -541,7 +545,7 @@ public void Queue(SpriteFont spriteFont, int codepoint, in Font.Character metric
var result = (BlitTask)state!;
result.BufferContainsValidData =
result.SpriteFont?.Font != null &&
TryBlitCharacter(result.SpriteFont.Font, result.Metrics, ref result.Buffer);
TryBlitCharacter(result.SpriteFont.Font, result.Metrics, ref result.Buffer, result.SpriteFont.PremultiplyAlpha);
return result;
}, task));
}
Expand Down

0 comments on commit 88d3754

Please sign in to comment.