Show More
Commit Description:
Add timers for Simulation and various engines...
Commit Description:
Add timers for Simulation and various engines
Starting to add additional timers for different stages of the process of
updating in order to get more insight into what is slowing it down.
The update takes 9ms, which is much longer than it used to.
Engine-specific timers are coming later.
References:
File last commit:
Show/Diff file:
Action:
SpriteFontPlus/src/FontStashSharp/FontSystem.cs
815 lines | 17.7 KiB | text/x-csharp | CSharpLexer
815 lines | 17.7 KiB | text/x-csharp | CSharpLexer
r0 | using System; | ||
using System.Collections.Generic; | |||
using System.Text; | |||
using Microsoft.Xna.Framework; | |||
using Microsoft.Xna.Framework.Graphics; | |||
namespace FontStashSharp | |||
{ | |||
internal class FontSystem | |||
{ | |||
private readonly Dictionary<int, Dictionary<int, FontGlyph>> _glyphs = new Dictionary<int, Dictionary<int, FontGlyph>>(); | |||
private readonly List<Font> _fonts = new List<Font>(); | |||
private float _ith; | |||
private float _itw; | |||
private FontAtlas _currentAtlas; | |||
private Point _size; | |||
private int _fontSize; | |||
public int FontSize | |||
{ | |||
get | |||
{ | |||
return _fontSize; | |||
} | |||
set | |||
{ | |||
if (value == _fontSize) | |||
{ | |||
return; | |||
} | |||
_fontSize = value; | |||
foreach (var f in _fonts) | |||
{ | |||
f.Recalculate(_fontSize); | |||
} | |||
} | |||
} | |||
public readonly int Blur; | |||
public float Spacing; | |||
public Vector2 Scale; | |||
public bool UseKernings = true; | |||
public int? DefaultCharacter = ' '; | |||
public FontAtlas CurrentAtlas | |||
{ | |||
get | |||
{ | |||
if (_currentAtlas == null) | |||
{ | |||
_currentAtlas = new FontAtlas(_size.X, _size.Y, 256); | |||
Atlases.Add(_currentAtlas); | |||
} | |||
return _currentAtlas; | |||
} | |||
} | |||
public List<FontAtlas> Atlases { get; } = new List<FontAtlas>(); | |||
public event EventHandler CurrentAtlasFull; | |||
public FontSystem(int width, int height, int blur = 0) | |||
{ | |||
if (width <= 0) | |||
{ | |||
throw new ArgumentOutOfRangeException(nameof(width)); | |||
} | |||
if (height <= 0) | |||
{ | |||
throw new ArgumentOutOfRangeException(nameof(height)); | |||
} | |||
if (blur < 0 || blur > 20) | |||
{ | |||
throw new ArgumentOutOfRangeException(nameof(blur)); | |||
} | |||
Blur = blur; | |||
_size = new Point(width, height); | |||
_itw = 1.0f / _size.X; | |||
_ith = 1.0f / _size.Y; | |||
ClearState(); | |||
} | |||
public void ClearState() | |||
{ | |||
FontSize = 12; | |||
Spacing = 0; | |||
} | |||
public void AddFontMem(byte[] data) | |||
{ | |||
var font = Font.FromMemory(data); | |||
font.Recalculate(FontSize); | |||
_fonts.Add(font); | |||
} | |||
private Dictionary<int, FontGlyph> GetGlyphsCollection(int size) | |||
{ | |||
Dictionary<int, FontGlyph> result; | |||
if (_glyphs.TryGetValue(size, out result)) | |||
{ | |||
return result; | |||
} | |||
result = new Dictionary<int, FontGlyph>(); | |||
_glyphs[size] = result; | |||
return result; | |||
} | |||
private void PreDraw(string str, out Dictionary<int, FontGlyph> glyphs, out float ascent, out float lineHeight) | |||
{ | |||
glyphs = GetGlyphsCollection(FontSize); | |||
// Determine ascent and lineHeight from first character | |||
ascent = 0; | |||
lineHeight = 0; | |||
for (int i = 0; i < str.Length; i += char.IsSurrogatePair(str, i) ? 2 : 1) | |||
{ | |||
var codepoint = char.ConvertToUtf32(str, i); | |||
var glyph = GetGlyph(null, glyphs, codepoint); | |||
if (glyph == null) | |||
{ | |||
continue; | |||
} | |||
ascent = glyph.Font.Ascent; | |||
lineHeight = glyph.Font.LineHeight; | |||
break; | |||
} | |||
} | |||
public float DrawText(SpriteBatch batch, float x, float y, string str, Color color, float depth) | |||
{ | |||
if (string.IsNullOrEmpty(str)) return 0.0f; | |||
Dictionary<int, FontGlyph> glyphs; | |||
float ascent, lineHeight; | |||
PreDraw(str, out glyphs, out ascent, out lineHeight); | |||
float originX = 0.0f; | |||
float originY = 0.0f; | |||
originY += ascent; | |||
FontGlyph prevGlyph = null; | |||
var q = new FontGlyphSquad(); | |||
for (int i = 0; i < str.Length; i += char.IsSurrogatePair(str, i) ? 2 : 1) | |||
{ | |||
var codepoint = char.ConvertToUtf32(str, i); | |||
if (codepoint == '\n') | |||
{ | |||
originX = 0.0f; | |||
originY += lineHeight; | |||
prevGlyph = null; | |||
continue; | |||
} | |||
var glyph = GetGlyph(batch.GraphicsDevice, glyphs, codepoint); | |||
if (glyph == null) | |||
{ | |||
continue; | |||
} | |||
GetQuad(glyph, prevGlyph, Spacing, ref originX, ref originY, ref q); | |||
if (!glyph.IsEmpty) | |||
{ | |||
q.X0 = (int)(q.X0 * Scale.X); | |||
q.X1 = (int)(q.X1 * Scale.X); | |||
q.Y0 = (int)(q.Y0 * Scale.Y); | |||
q.Y1 = (int)(q.Y1 * Scale.Y); | |||
var destRect = new Rectangle((int)(x + q.X0), | |||
(int)(y + q.Y0), | |||
(int)(q.X1 - q.X0), | |||
(int)(q.Y1 - q.Y0)); | |||
var sourceRect = new Rectangle((int)(q.S0 * _size.X), | |||
(int)(q.T0 * _size.Y), | |||
(int)((q.S1 - q.S0) * _size.X), | |||
(int)((q.T1 - q.T0) * _size.Y)); | |||
batch.Draw(glyph.Atlas.Texture, | |||
destRect, | |||
sourceRect, | |||
color, | |||
0f, | |||
Vector2.Zero, | |||
SpriteEffects.None, | |||
depth); | |||
} | |||
prevGlyph = glyph; | |||
} | |||
return x; | |||
} | |||
public float DrawText(SpriteBatch batch, float x, float y, string str, Color[] glyphColors, float depth) | |||
{ | |||
if (string.IsNullOrEmpty(str)) return 0.0f; | |||
Dictionary<int, FontGlyph> glyphs; | |||
float ascent, lineHeight; | |||
PreDraw(str, out glyphs, out ascent, out lineHeight); | |||
float originX = 0.0f; | |||
float originY = 0.0f; | |||
originY += ascent; | |||
FontGlyph prevGlyph = null; | |||
var pos = 0; | |||
var q = new FontGlyphSquad(); | |||
for (int i = 0; i < str.Length; i += char.IsSurrogatePair(str, i) ? 2 : 1) | |||
{ | |||
var codepoint = char.ConvertToUtf32(str, i); | |||
if (codepoint == '\n') | |||
{ | |||
originX = 0.0f; | |||
originY += lineHeight; | |||
prevGlyph = null; | |||
++pos; | |||
continue; | |||
} | |||
var glyph = GetGlyph(batch.GraphicsDevice, glyphs, codepoint); | |||
if (glyph == null) | |||
{ | |||
++pos; | |||
continue; | |||
} | |||
GetQuad(glyph, prevGlyph, Spacing, ref originX, ref originY, ref q); | |||
if (!glyph.IsEmpty) | |||
{ | |||
q.X0 = (int)(q.X0 * Scale.X); | |||
q.X1 = (int)(q.X1 * Scale.X); | |||
q.Y0 = (int)(q.Y0 * Scale.Y); | |||
q.Y1 = (int)(q.Y1 * Scale.Y); | |||
var destRect = new Rectangle((int)(x + q.X0), | |||
(int)(y + q.Y0), | |||
(int)(q.X1 - q.X0), | |||
(int)(q.Y1 - q.Y0)); | |||
var sourceRect = new Rectangle((int)(q.S0 * _size.X), | |||
(int)(q.T0 * _size.Y), | |||
(int)((q.S1 - q.S0) * _size.X), | |||
(int)((q.T1 - q.T0) * _size.Y)); | |||
batch.Draw(glyph.Atlas.Texture, | |||
destRect, | |||
sourceRect, | |||
glyphColors[pos], | |||
0f, | |||
Vector2.Zero, | |||
SpriteEffects.None, | |||
depth); | |||
} | |||
prevGlyph = glyph; | |||
++pos; | |||
} | |||
return x; | |||
} | |||
private void PreDraw(StringBuilder str, out Dictionary<int, FontGlyph> glyphs, out float ascent, out float lineHeight) | |||
{ | |||
glyphs = GetGlyphsCollection(FontSize); | |||
// Determine ascent and lineHeight from first character | |||
ascent = 0; | |||
lineHeight = 0; | |||
for (int i = 0; i < str.Length; i += StringBuilderIsSurrogatePair(str, i) ? 2 : 1) | |||
{ | |||
var codepoint = StringBuilderConvertToUtf32(str, i); | |||
var glyph = GetGlyph(null, glyphs, codepoint); | |||
if (glyph == null) | |||
{ | |||
continue; | |||
} | |||
ascent = glyph.Font.Ascent; | |||
lineHeight = glyph.Font.LineHeight; | |||
break; | |||
} | |||
} | |||
public float DrawText(SpriteBatch batch, float x, float y, StringBuilder str, Color color, float depth) | |||
{ | |||
if (str == null || str.Length == 0) return 0.0f; | |||
Dictionary<int, FontGlyph> glyphs; | |||
float ascent, lineHeight; | |||
PreDraw(str, out glyphs, out ascent, out lineHeight); | |||
float originX = 0.0f; | |||
float originY = 0.0f; | |||
originY += ascent; | |||
FontGlyph prevGlyph = null; | |||
var q = new FontGlyphSquad(); | |||
for (int i = 0; i < str.Length; i += StringBuilderIsSurrogatePair(str, i) ? 2 : 1) | |||
{ | |||
var codepoint = StringBuilderConvertToUtf32(str, i); | |||
if (codepoint == '\n') | |||
{ | |||
originX = 0.0f; | |||
originY += lineHeight; | |||
prevGlyph = null; | |||
continue; | |||
} | |||
var glyph = GetGlyph(batch.GraphicsDevice, glyphs, codepoint); | |||
if (glyph == null) | |||
{ | |||
continue; | |||
} | |||
GetQuad(glyph, prevGlyph, Spacing, ref originX, ref originY, ref q); | |||
if (!glyph.IsEmpty) | |||
{ | |||
q.X0 = (int)(q.X0 * Scale.X); | |||
q.X1 = (int)(q.X1 * Scale.X); | |||
q.Y0 = (int)(q.Y0 * Scale.Y); | |||
q.Y1 = (int)(q.Y1 * Scale.Y); | |||
var destRect = new Rectangle((int)(x + q.X0), | |||
(int)(y + q.Y0), | |||
(int)(q.X1 - q.X0), | |||
(int)(q.Y1 - q.Y0)); | |||
var sourceRect = new Rectangle((int)(q.S0 * _size.X), | |||
(int)(q.T0 * _size.Y), | |||
(int)((q.S1 - q.S0) * _size.X), | |||
(int)((q.T1 - q.T0) * _size.Y)); | |||
batch.Draw(glyph.Atlas.Texture, | |||
destRect, | |||
sourceRect, | |||
color, | |||
0f, | |||
Vector2.Zero, | |||
SpriteEffects.None, | |||
depth); | |||
} | |||
prevGlyph = glyph; | |||
} | |||
return x; | |||
} | |||
public float DrawText(SpriteBatch batch, float x, float y, StringBuilder str, Color[] glyphColors, float depth) | |||
{ | |||
if (str == null || str.Length == 0) return 0.0f; | |||
Dictionary<int, FontGlyph> glyphs; | |||
float ascent, lineHeight; | |||
PreDraw(str, out glyphs, out ascent, out lineHeight); | |||
float originX = 0.0f; | |||
float originY = 0.0f; | |||
originY += ascent; | |||
FontGlyph prevGlyph = null; | |||
var pos = 0; | |||
var q = new FontGlyphSquad(); | |||
for (int i = 0; i < str.Length; i += StringBuilderIsSurrogatePair(str, i) ? 2 : 1) | |||
{ | |||
var codepoint = StringBuilderConvertToUtf32(str, i); | |||
if (codepoint == '\n') | |||
{ | |||
originX = 0.0f; | |||
originY += lineHeight; | |||
prevGlyph = null; | |||
++pos; | |||
continue; | |||
} | |||
var glyph = GetGlyph(batch.GraphicsDevice, glyphs, codepoint); | |||
if (glyph == null) | |||
{ | |||
++pos; | |||
continue; | |||
} | |||
GetQuad(glyph, prevGlyph, Spacing, ref originX, ref originY, ref q); | |||
if (!glyph.IsEmpty) | |||
{ | |||
q.X0 = (int)(q.X0 * Scale.X); | |||
q.X1 = (int)(q.X1 * Scale.X); | |||
q.Y0 = (int)(q.Y0 * Scale.Y); | |||
q.Y1 = (int)(q.Y1 * Scale.Y); | |||
var destRect = new Rectangle((int)(x + q.X0), | |||
(int)(y + q.Y0), | |||
(int)(q.X1 - q.X0), | |||
(int)(q.Y1 - q.Y0)); | |||
var sourceRect = new Rectangle((int)(q.S0 * _size.X), | |||
(int)(q.T0 * _size.Y), | |||
(int)((q.S1 - q.S0) * _size.X), | |||
(int)((q.T1 - q.T0) * _size.Y)); | |||
batch.Draw(glyph.Atlas.Texture, | |||
destRect, | |||
sourceRect, | |||
glyphColors[pos], | |||
0f, | |||
Vector2.Zero, | |||
SpriteEffects.None, | |||
depth); | |||
} | |||
prevGlyph = glyph; | |||
++pos; | |||
} | |||
return x; | |||
} | |||
public float TextBounds(float x, float y, string str, ref Bounds bounds) | |||
{ | |||
if (string.IsNullOrEmpty(str)) return 0.0f; | |||
Dictionary<int, FontGlyph> glyphs; | |||
float ascent, lineHeight; | |||
PreDraw(str, out glyphs, out ascent, out lineHeight); | |||
var q = new FontGlyphSquad(); | |||
y += ascent; | |||
float minx, maxx, miny, maxy; | |||
minx = maxx = x; | |||
miny = maxy = y; | |||
float startx = x; | |||
FontGlyph prevGlyph = null; | |||
for (int i = 0; i < str.Length; i += char.IsSurrogatePair(str, i) ? 2 : 1) | |||
{ | |||
var codepoint = char.ConvertToUtf32(str, i); | |||
if (codepoint == '\n') | |||
{ | |||
x = startx; | |||
y += lineHeight; | |||
prevGlyph = null; | |||
continue; | |||
} | |||
var glyph = GetGlyph(null, glyphs, codepoint); | |||
if (glyph == null) | |||
{ | |||
continue; | |||
} | |||
GetQuad(glyph, prevGlyph, Spacing, ref x, ref y, ref q); | |||
if (q.X0 < minx) | |||
minx = q.X0; | |||
if (x > maxx) | |||
maxx = x; | |||
if (q.Y0 < miny) | |||
miny = q.Y0; | |||
if (q.Y1 > maxy) | |||
maxy = q.Y1; | |||
prevGlyph = glyph; | |||
} | |||
float advance = x - startx; | |||
bounds.X = minx; | |||
bounds.Y = miny; | |||
bounds.X2 = maxx; | |||
bounds.Y2 = maxy; | |||
return advance; | |||
} | |||
public float TextBounds(float x, float y, StringBuilder str, ref Bounds bounds) | |||
{ | |||
if (str == null || str.Length == 0) return 0.0f; | |||
Dictionary<int, FontGlyph> glyphs; | |||
float ascent, lineHeight; | |||
PreDraw(str, out glyphs, out ascent, out lineHeight); | |||
var q = new FontGlyphSquad(); | |||
y += ascent; | |||
float minx, maxx, miny, maxy; | |||
minx = maxx = x; | |||
miny = maxy = y; | |||
float startx = x; | |||
FontGlyph prevGlyph = null; | |||
for (int i = 0; i < str.Length; i += StringBuilderIsSurrogatePair(str, i) ? 2 : 1) | |||
{ | |||
var codepoint = StringBuilderConvertToUtf32(str, i); | |||
if (codepoint == '\n') | |||
{ | |||
x = startx; | |||
y += lineHeight; | |||
prevGlyph = null; | |||
continue; | |||
} | |||
var glyph = GetGlyph(null, glyphs, codepoint); | |||
if (glyph == null) | |||
{ | |||
continue; | |||
} | |||
GetQuad(glyph, prevGlyph, Spacing, ref x, ref y, ref q); | |||
if (q.X0 < minx) | |||
minx = q.X0; | |||
if (x > maxx) | |||
maxx = x; | |||
if (q.Y0 < miny) | |||
miny = q.Y0; | |||
if (q.Y1 > maxy) | |||
maxy = q.Y1; | |||
prevGlyph = glyph; | |||
} | |||
float advance = x - startx; | |||
bounds.X = minx; | |||
bounds.Y = miny; | |||
bounds.X2 = maxx; | |||
bounds.Y2 = maxy; | |||
return advance; | |||
} | |||
public List<Rectangle> GetGlyphRects(float x, float y, string str){ | |||
List<Rectangle> Rects = new List<Rectangle>(); | |||
if (string.IsNullOrEmpty(str)) return Rects; | |||
Dictionary<int, FontGlyph> glyphs; | |||
float ascent, lineHeight; | |||
PreDraw(str, out glyphs, out ascent, out lineHeight); | |||
var q = new FontGlyphSquad(); | |||
y += ascent; | |||
float minx, maxx, miny, maxy; | |||
minx = maxx = x; | |||
miny = maxy = y; | |||
float startx = x; | |||
FontGlyph prevGlyph = null; | |||
for (int i = 0; i < str.Length; i += char.IsSurrogatePair(str, i) ? 2 : 1) | |||
{ | |||
var codepoint = char.ConvertToUtf32(str, i); | |||
if (codepoint == '\n') | |||
{ | |||
x = startx; | |||
y += lineHeight; | |||
prevGlyph = null; | |||
continue; | |||
} | |||
var glyph = GetGlyph(null, glyphs, codepoint); | |||
if (glyph == null) | |||
{ | |||
continue; | |||
} | |||
GetQuad(glyph, prevGlyph, Spacing, ref x, ref y, ref q); | |||
Rects.Add(new Rectangle((int)q.X0, (int)q.Y0, (int)(q.X1-q.X0), (int)(q.Y1-q.Y0))); | |||
prevGlyph = glyph; | |||
} | |||
return Rects; | |||
} | |||
public List<Rectangle> GetGlyphRects(float x, float y, StringBuilder str){ | |||
List<Rectangle> Rects = new List<Rectangle>(); | |||
if (str == null || str.Length == 0) return Rects; | |||
Dictionary<int, FontGlyph> glyphs; | |||
float ascent, lineHeight; | |||
PreDraw(str, out glyphs, out ascent, out lineHeight); | |||
var q = new FontGlyphSquad(); | |||
y += ascent; | |||
float minx, maxx, miny, maxy; | |||
minx = maxx = x; | |||
miny = maxy = y; | |||
float startx = x; | |||
FontGlyph prevGlyph = null; | |||
for (int i = 0; i < str.Length; i += StringBuilderIsSurrogatePair(str, i) ? 2 : 1) | |||
{ | |||
var codepoint = StringBuilderConvertToUtf32(str, i); | |||
if (codepoint == '\n') | |||
{ | |||
x = startx; | |||
y += lineHeight; | |||
prevGlyph = null; | |||
continue; | |||
} | |||
var glyph = GetGlyph(null, glyphs, codepoint); | |||
if (glyph == null) | |||
{ | |||
continue; | |||
} | |||
GetQuad(glyph, prevGlyph, Spacing, ref x, ref y, ref q); | |||
Rects.Add(new Rectangle((int)q.X0, (int)q.Y0, (int)(q.X1-q.X0), (int)(q.Y1-q.Y0))); | |||
prevGlyph = glyph; | |||
} | |||
return Rects; | |||
} | |||
bool StringBuilderIsSurrogatePair(StringBuilder sb, int index) | |||
{ | |||
if (index + 1 < sb.Length) | |||
return char.IsSurrogatePair(sb[index], sb[index + 1]); | |||
return false; | |||
} | |||
int StringBuilderConvertToUtf32(StringBuilder sb, int index) | |||
{ | |||
if (!char.IsHighSurrogate(sb[index])) | |||
return sb[index]; | |||
return char.ConvertToUtf32(sb[index], sb[index + 1]); | |||
} | |||
public void Reset(int width, int height) | |||
{ | |||
Atlases.Clear(); | |||
_glyphs.Clear(); | |||
if (width == _size.X && height == _size.Y) | |||
return; | |||
_size = new Point(width, height); | |||
_itw = 1.0f / _size.X; | |||
_ith = 1.0f / _size.Y; | |||
} | |||
public void Reset() | |||
{ | |||
Reset(_size.X, _size.Y); | |||
} | |||
private int GetCodepointIndex(int codepoint, out Font font) | |||
{ | |||
font = null; | |||
int g = 0; | |||
foreach (var f in _fonts) | |||
{ | |||
g = f.GetGlyphIndex(codepoint); | |||
if (g != 0) | |||
{ | |||
font = f; | |||
break; | |||
} | |||
} | |||
return g; | |||
} | |||
private FontGlyph GetGlyphWithoutBitmap(Dictionary<int, FontGlyph> glyphs, int codepoint) | |||
{ | |||
FontGlyph glyph = null; | |||
if (glyphs.TryGetValue(codepoint, out glyph)) | |||
{ | |||
return glyph; | |||
} | |||
Font font; | |||
var g = GetCodepointIndex(codepoint, out font); | |||
if (g == 0) | |||
{ | |||
return null; | |||
} | |||
int advance = 0, lsb = 0, x0 = 0, y0 = 0, x1 = 0, y1 = 0; | |||
font.BuildGlyphBitmap(g, FontSize, font.Scale, ref advance, ref lsb, ref x0, ref y0, ref x1, ref y1); | |||
var gw = x1 - x0; | |||
var gh = y1 - y0; | |||
glyph = new FontGlyph | |||
{ | |||
Font = font, | |||
Codepoint = codepoint, | |||
Size = FontSize, | |||
Index = g, | |||
Bounds = new Rectangle(0, 0, gw, gh), | |||
XAdvance = (int)(font.Scale * advance * 10.0f), | |||
XOffset = x0, | |||
YOffset = y0 | |||
}; | |||
glyphs[codepoint] = glyph; | |||
return glyph; | |||
} | |||
private FontGlyph GetGlyphInternal(GraphicsDevice graphicsDevice, Dictionary<int, FontGlyph> glyphs, int codepoint) | |||
{ | |||
var glyph = GetGlyphWithoutBitmap(glyphs, codepoint); | |||
if (glyph == null) | |||
{ | |||
return null; | |||
} | |||
if (graphicsDevice == null || glyph.Atlas != null || glyph.IsEmpty) | |||
return glyph; | |||
var currentAtlas = CurrentAtlas; | |||
int gx = 0, gy = 0; | |||
var gw = glyph.Bounds.Width; | |||
var gh = glyph.Bounds.Height; | |||
if (!currentAtlas.AddRect(gw, gh, ref gx, ref gy)) | |||
{ | |||
CurrentAtlasFull?.Invoke(this, EventArgs.Empty); | |||
// This code will force creation of new atlas | |||
_currentAtlas = null; | |||
currentAtlas = CurrentAtlas; | |||
// Try to add again | |||
if (!currentAtlas.AddRect(gw, gh, ref gx, ref gy)) | |||
{ | |||
throw new Exception(string.Format("Could not add rect to the newly created atlas. gw={0}, gh={1}", gw, gh)); | |||
} | |||
} | |||
glyph.Bounds.X = gx; | |||
glyph.Bounds.Y = gy; | |||
currentAtlas.RenderGlyph(graphicsDevice, glyph); | |||
glyph.Atlas = currentAtlas; | |||
return glyph; | |||
} | |||
private FontGlyph GetGlyph(GraphicsDevice graphicsDevice, Dictionary<int, FontGlyph> glyphs, int codepoint) | |||
{ | |||
var result = GetGlyphInternal(graphicsDevice, glyphs, codepoint); | |||
if (result == null && DefaultCharacter != null) | |||
{ | |||
result = GetGlyphInternal(graphicsDevice, glyphs, DefaultCharacter.Value); | |||
} | |||
return result; | |||
} | |||
private void GetQuad(FontGlyph glyph, FontGlyph prevGlyph, float spacing, ref float x, ref float y, ref FontGlyphSquad q) | |||
{ | |||
if (prevGlyph != null) | |||
{ | |||
float adv = 0; | |||
if (UseKernings && glyph.Font == prevGlyph.Font) | |||
{ | |||
adv = prevGlyph.GetKerning(glyph) * glyph.Font.Scale; | |||
} | |||
x += (int)(adv + spacing + 0.5f); | |||
} | |||
float rx = x + glyph.XOffset; | |||
float ry = y + glyph.YOffset; | |||
q.X0 = rx; | |||
q.Y0 = ry; | |||
q.X1 = rx + glyph.Bounds.Width; | |||
q.Y1 = ry + glyph.Bounds.Height; | |||
q.S0 = glyph.Bounds.X * _itw; | |||
q.T0 = glyph.Bounds.Y * _ith; | |||
q.S1 = glyph.Bounds.Right * _itw; | |||
q.T1 = glyph.Bounds.Bottom * _ith; | |||
x += (int)(glyph.XAdvance / 10.0f + 0.5f); | |||
} | |||
} | |||
} |