public Vector2 MeasureString(string text) { var pairs = Font.StringToPair; var activeFont = this; if (string.IsNullOrEmpty(text)) { return(new Vector2(0, Height / VectorScale)); } var size = new Vector2(0, Height / VectorScale); var subScale = 1f; MSDFGlyph next = null; if (text.Length > 0) { var c = text[0]; next = GetGlyph(c); } for (int i = 0; i < text.Length; i++) { var glyph = next; if (next == null) { if (i + 1 >= text.Length) { break; } var c = text[i + 1]; next = GetGlyph(c); continue; } if (activeFont != next.Font) { activeFont = next.Font; pairs = glyph.Font.Info.pairs; subScale = (activeFont != this) ? activeFont.VectorScale / VectorScale : 1f; } size.X += glyph.Glyph.Metrics.Advance * subScale; if (i < text.Length - 1) { var c = text[i + 1]; next = GetGlyph(c); if (next != null) { KerningPair pair; if (pairs.TryGetValue(new string(new char[] { glyph.Glyph.Character, next.Glyph.Character }), out pair)) { size.X += pair.Advance * subScale; } } } } return(size); }
public void Draw(GraphicsDevice gd, string text, Vector2 pos, Color color, Vector2 scale, Matrix?mat) { if (string.IsNullOrEmpty(text)) { return; } var point = new Vector2(0, 0); var atlas = GetAtlas(gd); var wv = Matrix.CreateScale(scale.X, scale.Y, 1) * Matrix.CreateTranslation(pos.X, pos.Y, 0); if (mat != null) { wv = wv * mat.Value; wv.Decompose(out var scale2, out var quat, out var trans); scale.X = scale2.X; scale.Y = scale2.Y; } var wvp = wv * Matrix.CreateOrthographicOffCenter(new Rectangle(0, 0, gd.Viewport.Width, gd.Viewport.Height), -0.1f, 1f); var effect = MSDFEffect; var groups = new Dictionary <MSDFFont, MSDFRenderGroup>(); var activeFont = this; var itemW = Info.itemW; var itemH = Info.itemH; var textureWidth = Info.textureWidth; var textureHeight = Info.textureHeight; var cutUX = Info.cutUX; var cutUY = Info.cutUY; var uW = Info.uW; var uH = Info.uH; var atlasWidth = Info.atlasWidth; var pairs = Info.pairs; var data = new MSDFRenderGroup(this); groups[this] = data; var verts = data.Vertices; var inds = data.Indices; effect.Parameters["WorldViewProjection"].SetValue(wvp); effect.Parameters["Color"].SetValue(color.ToVector4()); effect.CurrentTechnique = effect.Techniques[0]; var subScale = 1f; MSDFGlyph next = null; if (text.Length > 0) { var c = text[0]; next = GetGlyph(c); } for (int i = 0; i < text.Length; i++) { var glyph = next; if (glyph == null) { if (i + 1 >= text.Length) { break; } var c = text[i + 1]; next = GetGlyph(c); continue; } if (glyph.Font != activeFont) { activeFont = glyph.Font; subScale = (activeFont != this) ? activeFont.VectorScale / VectorScale : 1f; var ainfo = activeFont.Info; itemW = ainfo.itemW; itemH = ainfo.itemH; textureWidth = ainfo.textureWidth; textureHeight = ainfo.textureHeight; cutUX = ainfo.cutUX; cutUY = ainfo.cutUY; uW = ainfo.uW; uH = ainfo.uH; atlasWidth = ainfo.atlasWidth; pairs = ainfo.pairs; MSDFRenderGroup mdata = null; if (!groups.TryGetValue(activeFont, out mdata)) { mdata = new MSDFRenderGroup(activeFont); groups[activeFont] = mdata; } verts = mdata.Vertices; inds = mdata.Indices; } var fglyph = glyph.Glyph; var mscale = fglyph.Metrics.Scale; var left = point.X - (fglyph.Metrics.Translation.X - 1 / mscale) * subScale; var bottom = point.Y + (fglyph.Metrics.Translation.Y + activeFont.YOff / activeFont.VectorScale - 1 / mscale) * subScale; mscale /= subScale; var glyphHeight = (textureHeight - 2) / mscale; var glyphWidth = (textureWidth - 2) / mscale; var right = left + glyphWidth; var top = bottom - glyphHeight; var tx = (fglyph.AtlasIndex % atlasWidth) * itemW + cutUX; var ty = (fglyph.AtlasIndex / atlasWidth) * itemH + cutUY; var derivative = (new Vector2(uW / (right - left), uH / (bottom - top)) / scale) / 2; if (!char.IsWhiteSpace(fglyph.Character)) { RenderQuad(inds, verts, new Vector2(left, bottom), new Vector2(right, top), new Vector2(tx, ty + uH), new Vector2(tx + uW, ty), derivative); } point.X += fglyph.Metrics.Advance * subScale; if (i < text.Length - 1) { var c = text[i + 1]; next = GetGlyph(c); if (next != null) { KerningPair pair; if (pairs.TryGetValue(new string(new char[] { fglyph.Character, next.Glyph.Character }), out pair)) { point.X += pair.Advance * subScale; } } } } foreach (var group in groups.Values) { effect.Parameters["PxRange"].SetValue(group.Font.Font.PxRange); var groupAtlas = group.Font.GetAtlas(gd); effect.Parameters["TextureSize"].SetValue(new Vector2(groupAtlas.Width, groupAtlas.Height)); effect.Parameters["GlyphTexture"].SetValue(groupAtlas); effect.CurrentTechnique.Passes[0].Apply(); if (group.Vertices.Count == 0) { continue; } gd.DrawUserIndexedPrimitives(PrimitiveType.TriangleList, group.Vertices.ToArray(), 0, group.Vertices.Count, group.Indices.ToArray(), 0, group.Indices.Count / 3); } }