Skip to content

Commit

Permalink
Fixes #33
Browse files Browse the repository at this point in the history
  • Loading branch information
Roman Shapiro committed May 8, 2020
1 parent d3373a2 commit 4bfa40f
Show file tree
Hide file tree
Showing 3 changed files with 238 additions and 2 deletions.
34 changes: 34 additions & 0 deletions src/DynamicSpriteFont.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text;

namespace SpriteFontPlus
{
Expand Down Expand Up @@ -131,6 +132,23 @@ public float DrawString(SpriteBatch batch, string text, Vector2 pos, Color color
return result;
}

public float DrawString(SpriteBatch batch, StringBuilder text, Vector2 pos, Color color)
{
return DrawString(batch, text, pos, color, Vector2.One);
}

public float DrawString(SpriteBatch batch, StringBuilder text, Vector2 pos, Color color, Vector2 scale, float depth = 0f)
{
_fontSystem.Color = color;
_fontSystem.Scale = scale;

var result = _fontSystem.DrawText(batch, pos.X, pos.Y, text, depth);

_fontSystem.Scale = Vector2.One;

return result;
}

public void AddTtf(byte[] ttf)
{
_fontSystem.AddFontMem(ttf);
Expand All @@ -149,6 +167,14 @@ public Vector2 MeasureString(string text)
return new Vector2(bounds.X2, bounds.Y2);
}

public Vector2 MeasureString(StringBuilder text)
{
Bounds bounds = new Bounds();
_fontSystem.TextBounds(0, 0, text, ref bounds);

return new Vector2(bounds.X2, bounds.Y2);
}

public Rectangle GetTextBounds(Vector2 position, string text)
{
Bounds bounds = new Bounds();
Expand All @@ -157,6 +183,14 @@ public Rectangle GetTextBounds(Vector2 position, string text)
return new Rectangle((int)bounds.X, (int)bounds.Y, (int)(bounds.X2 - bounds.X), (int)(bounds.Y2 - bounds.Y));
}

public Rectangle GetTextBounds(Vector2 position, StringBuilder text)
{
Bounds bounds = new Bounds();
_fontSystem.TextBounds(position.X, position.Y, text, ref bounds);

return new Rectangle((int)bounds.X, (int)bounds.Y, (int)(bounds.X2 - bounds.X), (int)(bounds.Y2 - bounds.Y));
}

public void Reset(int width, int height)
{
_fontSystem.Reset(width, height);
Expand Down
193 changes: 191 additions & 2 deletions src/FontStashSharp/FontSystem.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

Expand Down Expand Up @@ -202,6 +203,90 @@ public float DrawText(SpriteBatch batch, float x, float y, string str, float dep
return x;
}

public float DrawText(SpriteBatch batch, float x, float y, StringBuilder str, float depth)
{
if (str == null || str.Length == 0) return 0.0f;

var glyphs = GetGlyphsCollection(FontSize);

// Determine ascent and lineHeight from first character
float 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(batch.GraphicsDevice, glyphs, codepoint);
if (glyph == null)
{
continue;
}

ascent = glyph.Font.Ascent;
lineHeight = glyph.Font.LineHeight;
break;
}

var q = new FontGlyphSquad();

float originX = 0.0f;
float originY = 0.0f;

originY += ascent;

FontGlyph prevGlyph = null;
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;
}

if (!glyph.IsEmpty)
{
GetQuad(glyph, prevGlyph, Spacing, ref originX, ref originY, ref q);

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 TextBounds(float x, float y, string str, ref Bounds bounds)
{
if (string.IsNullOrEmpty(str)) return 0.0f;
Expand All @@ -226,6 +311,83 @@ public float TextBounds(float x, float y, string str, ref Bounds bounds)
}


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;
}

if (!glyph.IsEmpty)
{
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;

var glyphs = GetGlyphsCollection(FontSize);

// Determine ascent and lineHeight from first character
float 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;
}


var q = new FontGlyphSquad();
float startx = 0;
float advance = 0;
Expand All @@ -239,9 +401,9 @@ public float TextBounds(float x, float y, string str, ref Bounds bounds)

FontGlyph prevGlyph = null;

for (int i = 0; i < str.Length; i += char.IsSurrogatePair(str, i) ? 2 : 1)
for (int i = 0; i < str.Length; i += StringBuilderIsSurrogatePair(str, i) ? 2 : 1)
{
var codepoint = char.ConvertToUtf32(str, i);
var codepoint = StringBuilderConvertToUtf32(str, i);

if (codepoint == '\n')
{
Expand Down Expand Up @@ -283,6 +445,33 @@ public float TextBounds(float x, float y, string str, ref Bounds bounds)
return advance;
}

bool StringBuilderIsSurrogatePair(StringBuilder sb, int index)
{
if (sb == null)
throw new ArgumentNullException(nameof(sb));
if (index < 0 || index > sb.Length)
throw new ArgumentOutOfRangeException(nameof(index));
if (index + 1 < sb.Length)
return char.IsSurrogatePair(sb[index], sb[index + 1]);
return false;
}

int StringBuilderConvertToUtf32(StringBuilder sb, int index)
{
if (sb == null)
throw new ArgumentNullException(nameof(sb));
if (index < 0 || index > sb.Length)
throw new ArgumentOutOfRangeException(nameof(index));

if (!char.IsHighSurrogate(sb[index]))
return sb[index];

if (index >= sb.Length - 1)
throw new Exception("Invalid High Surrogate.");

return char.ConvertToUtf32(sb[index], sb[index + 1]);
}

public void Reset(int width, int height)
{
Atlases.Clear();
Expand Down
13 changes: 13 additions & 0 deletions src/SpriteBatchExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System.Text;

namespace SpriteFontPlus
{
Expand All @@ -16,5 +17,17 @@ public static float DrawString(this SpriteBatch batch, DynamicSpriteFont font,
{
return font.DrawString(batch, _string_, pos, color, scale);
}

public static float DrawString(this SpriteBatch batch, DynamicSpriteFont font,
StringBuilder _string_, Vector2 pos, Color color)
{
return font.DrawString(batch, _string_, pos, color);
}

public static float DrawString(this SpriteBatch batch, DynamicSpriteFont font,
StringBuilder _string_, Vector2 pos, Color color, Vector2 scale)
{
return font.DrawString(batch, _string_, pos, color, scale);
}
}
}

0 comments on commit 4bfa40f

Please sign in to comment.