private void SetupSpaceGlyphs(MSDFFontData fontData) { var space = fontData.GetGlyphById(SPACE_ID); if (null == space) { space = fontData.GetMGlyph(); } if (null == space) { space = fontData.GetGlyphByIndex(0); } var tabWidth = _tabSize * space.xadvance; _fallbackSpaceGlyph = space; _fallbackTabGlyph = new Glyph() { x = 0, y = 0, xadvance = tabWidth, id = TAB_ID, xoffset = 0, yoffset = 0, width = 0, height = 0, page = space.page, channel = space.channel, character = space.character, index = space.index, }; }
public Glyph GetMGlyph() { foreach (var str in M_WIDTH) { var id = MSDFFontData.GetCharCode(str); if (HasChar(id)) { return(GetGlyphById(id)); } } return(null); }
public static MeshInfo GetMeshInfo(string text, MSDFFontData fontData, bool flipY) { var glyphs = TextLayout.GetVisibleGlyphs(text, fontData); var positions = VertexUtil.CreateVerticesFromGlyphs(glyphs); var uvs = VertexUtil.CreateUVsFromGlyphs(glyphs, fontData.common.scaleW, fontData.common.scaleH, flipY); var width = positions[positions.Count - 1].x - positions[0].x; var maxY = positions.Max(v => v.y); var minY = positions.Min(v => v.y); var height = maxY - minY; Debug.Log($"max y : {maxY}, min y : {minY}, height : {height}"); return(new MeshInfo(positions.ToArray(), uvs.ToArray(), width, height)); }
private static float GetCapHeight(MSDFFontData fontData) { foreach (var str in CAP_HEIGHTS) { var id = MSDFFontData.GetCharCode(str); if (fontData.HasChar(id)) { return(fontData.GetGlyphById(id).height); } } return(0f); }
public static List <Metrics> GetLines(string text, MSDFFontData fontData, int?start = null, int?end = null, float?width = null, WrapMode mode = WrapMode.NONE, bool monospace = false) { if (0f == width && WrapMode.NO_WRAP == mode) { return(new List <Metrics>()); } var width_ = (float)(null != width ? width : float.MaxValue); var start_ = Mathf.Max(0, (int)(null != start ? start : 0)); var end_ = (int)(null != end ? end : text.Length); if (WrapMode.PRE == mode) { return(Pre(fontData, text, start_, end_, width_, monospace)); } else { return(Greedy(fontData, text, start_, end_, width_, mode, monospace)); } }
private static List <Metrics> Pre(MSDFFontData fontData, string text, int start, int end, float width, bool monospace) { var lines = new List <Metrics>(); var lineStart = start; for (var i = start; i < end && i < text.Length; ++i) { var chr = text[i]; var isNewline = _newline.IsMatch(chr.ToString()); if (isNewline || i == end - 1) { var lineEnd = isNewline ? i : i + 1; var measured = monospace ? Monospace(text, lineStart, lineEnd, width) : ComputeMetrics(fontData, text, lineStart, lineEnd, width); lines.Add(measured); lineStart = i + 1; } } return(lines); }
private static List <Metrics> Greedy(MSDFFontData fontData, string text, int start, int end, float width, WrapMode mode, bool monospace) { var lines = new List <Metrics>(); var testWidth = width; if (mode == WrapMode.NO_WRAP) { testWidth = float.MaxValue; } while (start < end && start < text.Length) { var newLine = IndexOf(text, _newlineChar, start, end); while (start < newLine) { if (!IsWhitespace(text[start].ToString())) { break; } ++start; } var measured = monospace ? Monospace(text, start, newLine, width) : ComputeMetrics(fontData, text, start, newLine, width); var lineEnd = start + (measured.end - measured.start); var nextStart = lineEnd + _newlineChar.Length; if (lineEnd < newLine) { while (lineEnd > start) { if (IsWhitespace(text[lineEnd].ToString())) { break; } --lineEnd; } if (lineEnd == start) { if (nextStart > start + _newlineChar.Length) { --nextStart; } lineEnd = nextStart; } else { nextStart = lineEnd; while (lineEnd > start) { if (!IsWhitespace(text[lineEnd - _newlineChar.Length].ToString())) { break; } --lineEnd; } } } if (lineEnd >= start) { var result = monospace ? Monospace(text, start, lineEnd, testWidth) : ComputeMetrics(fontData, text, start, lineEnd, testWidth); lines.Add(result); } start = nextStart; } return(lines); }
private static Metrics ComputeMetrics(MSDFFontData fontData, string text, int start, int end, float width, float?letterSpacing = null) { var spacing = null != letterSpacing ? letterSpacing : 0f; var curPen = 0f; var curWidth = 0f; var count = 0; Glyph glyph = null; Glyph lastGlyph = null; if (null == fontData || 0 == fontData.CharCount()) { return(new Metrics() { start = start, end = start, width = 0f }); } end = Mathf.Min(text.Length, end); for (var i = start; i < end; ++i) { var id = MSDFFontData.GetCharCode(text[i]); glyph = fontData.GetGlyphById(id); if (null != glyph) { var xoff = glyph.xoffset; var kern = null == lastGlyph ? 0f : fontData.GetKerningAmount(lastGlyph.id, glyph.id); curPen += kern; var nextPen = curPen + glyph.xadvance; var nextWidth = curPen + glyph.width; if (nextWidth >= width || nextPen >= width) { break; } curPen = nextPen; curWidth = nextWidth; lastGlyph = glyph; } ++count; } if (null != lastGlyph) { curWidth += lastGlyph.xoffset; } return(new Metrics() { start = start, end = start + count, width = curWidth }); }
public TextLayout(string text, MSDFFontData fontData, int tabSize = 4, int width = 0, float lineHeight = 0f, float letterSpacing = 0f, Align alignType = Align.LEFT) { glyphs = new List <ProcessedGlyph>(); Update(text, fontData, tabSize, width, lineHeight, letterSpacing); }
public static List <ProcessedGlyph> GetVisibleGlyphs(string text, MSDFFontData fontData, float tabSize = 4f, int width = 0, float lineHeight = 0f, float letterSpacing = 0f, Align alignType = Align.LEFT) { // setup space and tab var space = fontData.GetGlyphById(SPACE_ID); if (null == space) { space = fontData.GetMGlyph(); } if (null == space) { space = fontData.GetGlyphByIndex(0); } var fallbackSpaceGlyph = space; var fallbackTabGlyph = new Glyph() { x = 0, y = 0, xadvance = tabSize * space.xadvance, id = TextLayout.TAB_ID, xoffset = 0, yoffset = 0, width = 0, height = 0, page = space.page, channel = space.channel, character = space.character, index = space.index, }; // calculate layouts var glyphs = new List <ProcessedGlyph>(); var lines = WordWrapper.GetLines(text, fontData); var minWidth = width; glyphs.Clear(); var maxLineWidth = lines.Max(metrics => metrics.width); var x = 0f; var y = 0f; var lh = 0f == lineHeight ? fontData.common.lineHeight : lineHeight; var descender = lh - fontData.common.baseLine; var height = lh * lines.Count() - descender; y -= height; int lineIndex = 0; foreach (var line in lines) { var start = line.start; var end = line.end; var lineWidth = line.width; Glyph lastGlyph = null; for (var i = start; i < end; ++i) { var id = MSDFFontData.GetCharCode(text[i]); Glyph glyph; if (id == TAB_ID) { glyph = fallbackTabGlyph; } else if (id == SPACE_ID) { glyph = fallbackSpaceGlyph; } else { glyph = fontData.GetGlyphById(id); } if (null != glyph) { if (null != lastGlyph) { x += fontData.GetKerningAmount(lastGlyph.id, glyph.id); } var tx = x; if (Align.CENTER == alignType) { tx += (maxLineWidth - lineWidth) * 0.5f; } else if (Align.RIGHT == alignType) { tx += (maxLineWidth - lineWidth); } glyphs.Add(new ProcessedGlyph() { position = new Vector2(tx, y), glyph = glyph, index = i, line = lineIndex }); x += glyph.xadvance + letterSpacing; lastGlyph = glyph; } } y += lineHeight; x = 0; ++lineIndex; } return(glyphs.Where(g => g.glyph.width * g.glyph.height > 0).ToList()); }
private void Update(string text, MSDFFontData fontData, int tabSize = 4, int width = 0, float lineHeight = 0f, float letterSpacing = 0f, Align alignType = Align.LEFT) { SetupSpaceGlyphs(fontData); var lines = WordWrapper.GetLines(text, fontData); var minWidth = width; glyphs.Clear(); var maxLineWidth = lines.Max(metrics => metrics.width); var x = 0f; var y = 0f; var lh = 0f == lineHeight ? fontData.common.lineHeight : lineHeight; var baseline = fontData.common.baseLine; var descender = lh - baseline; var spacing = letterSpacing; var height = lh * lines.Count() - descender; var align = alignType; y -= height; _width = maxLineWidth; _height = height; _descender = lineHeight - baseline; _baseline = baseline; _xHeight = GetXHeight(fontData); _capHeight = GetCapHeight(fontData); _lineHeight = lineHeight; _ascender = lineHeight - descender - _xHeight; int lineIndex = 0; foreach (var line in lines) { var start = line.start; var end = line.end; var lineWidth = line.width; Glyph lastGlyph = null; for (var i = start; i < end; ++i) { var id = MSDFFontData.GetCharCode(text[i]); var glyph = fontData.GetGlyphById(id); if (null != glyph) { if (null != lastGlyph) { x += fontData.GetKerningAmount(lastGlyph.id, glyph.id); } var tx = x; if (Align.CENTER == align) { tx += (maxLineWidth - lineWidth) * 0.5f; } else if (Align.RIGHT == align) { tx += (maxLineWidth - lineWidth); } glyphs.Add(new ProcessedGlyph() { position = new Vector2(tx, y), glyph = glyph, index = i, line = lineIndex }); x += glyph.xadvance + letterSpacing; lastGlyph = glyph; } } y += lineHeight; x = 0; ++lineIndex; } _linesTotal = lines.Count; }