Added unit measurements to bitmap font.
This commit is contained in:
parent
5a8e7a9ccb
commit
30d7221a85
@ -17,27 +17,28 @@ namespace SlatedGameToolkit.Framework.Graphics.Text
|
|||||||
public class BitmapFont : IDisposable
|
public class BitmapFont : IDisposable
|
||||||
{
|
{
|
||||||
private GLContext context;
|
private GLContext context;
|
||||||
LRUCache<char, int> glyphIndices;
|
private LRUCache<char, int> glyphIndices;
|
||||||
|
private LRUCache<char, CharacterMetrics> metricsCache;
|
||||||
|
private LRUCache<(int, int), int> kerningCache;
|
||||||
FontTexture[] textures;
|
FontTexture[] textures;
|
||||||
StbTrueType.stbtt_fontinfo info;
|
StbTrueType.stbtt_fontinfo info;
|
||||||
private int spaceAdvance;
|
private int spaceAdvance;
|
||||||
private float scale;
|
private float scale;
|
||||||
private float pixelHeight;
|
|
||||||
public float PixelHeight
|
public float PixelHeight
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return pixelHeight;
|
return scale * (ascent - descent);
|
||||||
}
|
}
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
this.scale = StbTrueType.stbtt_ScaleForPixelHeight(info, value);
|
this.scale = value / (ascent - descent);
|
||||||
this.pixelHeight = value;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private Dictionary<(char, float), int> glyphTexLocations = new Dictionary<(char, float), int>();
|
private Dictionary<(char, float), int> glyphTexLocations = new Dictionary<(char, float), int>();
|
||||||
private LRUCache<char, CharacterMetrics> metricsCache;
|
|
||||||
private int ascent, descent, lineGap;
|
private int ascent, descent, lineGap;
|
||||||
|
public float PixelsPerUnitHeight { get; set; }
|
||||||
|
public float PixelsPerUnitWidth { get; set; }
|
||||||
private int drawingTo;
|
private int drawingTo;
|
||||||
private bool disposed;
|
private bool disposed;
|
||||||
|
|
||||||
@ -49,6 +50,7 @@ namespace SlatedGameToolkit.Framework.Graphics.Text
|
|||||||
|
|
||||||
this.glyphIndices = new LRUCache<char, int>(cacheSize);
|
this.glyphIndices = new LRUCache<char, int>(cacheSize);
|
||||||
this.metricsCache = new LRUCache<char, CharacterMetrics>(cacheSize);
|
this.metricsCache = new LRUCache<char, CharacterMetrics>(cacheSize);
|
||||||
|
this.kerningCache = new LRUCache<(int, int), int>(cacheSize);
|
||||||
this.textures = new FontTexture[textures];
|
this.textures = new FontTexture[textures];
|
||||||
|
|
||||||
this.context = glContext ?? WindowContextsManager.CurrentGL;
|
this.context = glContext ?? WindowContextsManager.CurrentGL;
|
||||||
@ -64,6 +66,11 @@ namespace SlatedGameToolkit.Framework.Graphics.Text
|
|||||||
this.ascent = ascent;
|
this.ascent = ascent;
|
||||||
this.descent = descent;
|
this.descent = descent;
|
||||||
this.lineGap = lineGap;
|
this.lineGap = lineGap;
|
||||||
|
|
||||||
|
int vWidth, vHeight, vX, vY;
|
||||||
|
context.GetViewport(out vX, out vY, out vWidth, out vHeight);
|
||||||
|
this.PixelsPerUnitWidth = vWidth;
|
||||||
|
this.PixelsPerUnitHeight = vHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
public BitmapFont(string path, GLContext glContext = null, int cacheSize = 1024, int textures = 2, uint textureSizes = 512) : this(File.ReadAllBytes(path), glContext, cacheSize, textures, textureSizes) {
|
public BitmapFont(string path, GLContext glContext = null, int cacheSize = 1024, int textures = 2, uint textureSizes = 512) : this(File.ReadAllBytes(path), glContext, cacheSize, textures, textureSizes) {
|
||||||
@ -107,17 +114,14 @@ namespace SlatedGameToolkit.Framework.Graphics.Text
|
|||||||
char[] chars = text.ToCharArray();
|
char[] chars = text.ToCharArray();
|
||||||
for (int i = 0; i < chars.Length; i++) {
|
for (int i = 0; i < chars.Length; i++) {
|
||||||
char c = chars[i];
|
char c = chars[i];
|
||||||
int glyphIndex = glyphIndices.ComputeIfNonExistent(c, (p) => StbTrueType.stbtt_FindGlyphIndex(info, p));
|
|
||||||
CharacterMetrics metrics = metricsCache.ComputeIfNonExistent(c, (p) => new CharacterMetrics(glyphIndex, info));
|
|
||||||
int viewWidth, viewHeight, vX, vY;
|
|
||||||
context.GetViewport(out vX, out vY, out viewWidth, out viewHeight);
|
|
||||||
|
|
||||||
if (c == ' ') {
|
if (c == ' ') {
|
||||||
currentPoint += (scale * spaceAdvance) / viewWidth;
|
currentPoint += (scale * spaceAdvance) / PixelsPerUnitWidth;
|
||||||
} else if (c == '\n') {
|
} else if (c == '\n') {
|
||||||
currentPoint = x;
|
currentPoint = x;
|
||||||
baseLine -= ((ascent - descent + lineGap) * scale) / viewHeight;
|
baseLine -= ((ascent - descent + lineGap) * scale) / PixelsPerUnitHeight;
|
||||||
} else {
|
} else {
|
||||||
|
int glyphIndex = glyphIndices.ComputeIfNonExistent(c, (p) => StbTrueType.stbtt_FindGlyphIndex(info, p));
|
||||||
|
CharacterMetrics metrics = metricsCache.ComputeIfNonExistent(c, (p) => new CharacterMetrics(glyphIndex, info));
|
||||||
//Check if glyph is loaded, if not, throw exception.
|
//Check if glyph is loaded, if not, throw exception.
|
||||||
if (!glyphTexLocations.ContainsKey((c, scale)) || !textures[glyphTexLocations[(c, scale)]].ContainsChar(c, scale)) {
|
if (!glyphTexLocations.ContainsKey((c, scale)) || !textures[glyphTexLocations[(c, scale)]].ContainsChar(c, scale)) {
|
||||||
throw new FrameworkUsageException(string.Format("Character \'{0}\' was not prepared and is missing!", c));
|
throw new FrameworkUsageException(string.Format("Character \'{0}\' was not prepared and is missing!", c));
|
||||||
@ -128,15 +132,15 @@ namespace SlatedGameToolkit.Framework.Graphics.Text
|
|||||||
RectangleF transformedTexBounds = texBounds.MultiplyBy(1f/texture.Length);
|
RectangleF transformedTexBounds = texBounds.MultiplyBy(1f/texture.Length);
|
||||||
transformedTexBounds.Y += transformedTexBounds.Height;
|
transformedTexBounds.Y += transformedTexBounds.Height;
|
||||||
transformedTexBounds.Height *= -1;
|
transformedTexBounds.Height *= -1;
|
||||||
RectangleF glyphBounds = new RectangleF(currentPoint, baseLine, texBounds.Width / viewWidth, texBounds.Height / viewHeight);
|
RectangleF glyphBounds = new RectangleF(currentPoint, baseLine, texBounds.Width / PixelsPerUnitWidth, texBounds.Height / PixelsPerUnitHeight);
|
||||||
glyphBounds.X += (metrics.leftSideBearing * scale) / viewWidth;
|
glyphBounds.X += (metrics.leftSideBearing * scale) / PixelsPerUnitWidth;
|
||||||
glyphBounds.Y += (metrics.vertOffset * scale) / viewHeight;
|
glyphBounds.Y += (metrics.vertOffset * scale) / PixelsPerUnitHeight;
|
||||||
|
|
||||||
batch.Draw(new RectangleMesh(glyphBounds, transformedTexBounds, texture, color));
|
batch.Draw(new RectangleMesh(glyphBounds, transformedTexBounds, texture, color));
|
||||||
currentPoint += (metrics.advanceWidth * scale) / viewWidth;
|
currentPoint += (metrics.advanceWidth * scale) / PixelsPerUnitWidth;
|
||||||
if (i + 1 < chars.Length) {
|
if (i + 1 < chars.Length) {
|
||||||
int nextGlyph = glyphIndices.ComputeIfNonExistent(chars[i + 1], (p) => StbTrueType.stbtt_FindGlyphIndex(info, p));
|
int nextGlyphIndex = glyphIndices.ComputeIfNonExistent(chars[i + 1], (p) => StbTrueType.stbtt_FindGlyphIndex(info, p));
|
||||||
currentPoint += (StbTrueType.stbtt_GetGlyphKernAdvance(info, glyphIndex, nextGlyph) * scale) / viewWidth;
|
currentPoint += (kerningCache.ComputeIfNonExistent((glyphIndex, nextGlyphIndex), (gIndices) => StbTrueType.stbtt_GetGlyphKernAdvance(info, gIndices.Item1, gIndices.Item2)) * scale) / PixelsPerUnitWidth;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user