{"action":"created","issue":{"url":"https://api.github.com/repos/libgdx/libgdx/issues/2955","labels_url":"https://api.github.com/repos/libgdx/libgdx/issues/2955/labels{/name}","comments_url":"https://api.github.com/repos/libgdx/libgdx/issues/2955/comments","events_url":"https://api.github.com/repos/libgdx/libgdx/issues/2955/events","html_url":"https://github.com/libgdx/libgdx/pull/2955","id":62846596,"number":2955,"title":"Separation of glyphs and characters for BitmapFontCache","user":{"login":"NathanSweet","id":434010,"avatar_url":"https://avatars.githubusercontent.com/u/434010?v=3","gravatar_id":"","url":"https://api.github.com/users/NathanSweet","html_url":"https://github.com/NathanSweet","followers_url":"https://api.github.com/users/NathanSweet/followers","following_url":"https://api.github.com/users/NathanSweet/following{/other_user}","gists_url":"https://api.github.com/users/NathanSweet/gists{/gist_id}","starred_url":"https://api.github.com/users/NathanSweet/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/NathanSweet/subscriptions","organizations_url":"https://api.github.com/users/NathanSweet/orgs","repos_url":"https://api.github.com/users/NathanSweet/repos","events_url":"https://api.github.com/users/NathanSweet/events{/privacy}","received_events_url":"https://api.github.com/users/NathanSweet/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":7,"created_at":"2015-03-19T01:51:58Z","updated_at":"2015-03-22T18:26:03Z","closed_at":null,"pull_request":{"url":"https://api.github.com/repos/libgdx/libgdx/pulls/2955","html_url":"https://github.com/libgdx/libgdx/pull/2955","diff_url":"https://github.com/libgdx/libgdx/pull/2955.diff","patch_url":"https://github.com/libgdx/libgdx/pull/2955.patch"},"body":"This PR refactors how BitmapFontCache works. Previously it was assumed each character in a string mapped to a glyph for display. As discussed in #1589, this is not the case for some types of font rendering. This PR has two main goals: 1) to separate characters and glyphs, 2) to make parsing the string and preparing for display cleaner. The new approach works like this:\r\n\r\n1. GlyphLayout, a new class, is given a string of characters. It first breaks the strings into \"runs\". A run is a string of characters all the same color and without newlines. The reason to break the text into runs is that each run can be \"shaped\" individually, which means to convert the characters into glyphs for display. When breaking the string into runs, GlyphLayout parses color markup tags and stores the color for each run.\r\n1. Next, the runs are shaped using a new BitmapFontData method, `getGlyphs`. This takes the characters for the run and generates both a list of glyphs and a list of positions for each glyph. The default implementation just looks up the glyph for the character as has always been done. A more complex implementation could use [HarfBuzz](http://www.freedesktop.org/wiki/Software/HarfBuzz/) or another lib to do the shaping.\r\n1. Next, the shaped runs are laid out. If wrapping is enabled and a run's glyphs exceed the wrap width, then glyphs are split for line wrapping using another new BitmapFontData method, `getWrapIndex`. The run is ended, the remaining glyphs are moved to a new run on the next line, and the layout process repeats. I'm not sure if line wrapping glyphs is the best solution, but at least where the wrap happens can be customized. Once all runs are laid out, if center or right alignment is requested then run positions are shifted appropriately.\r\n1. At this point GlyphLayout is done. It stores the `Array<GlyphRun>` and provides a width and height which is the bounds of all the runs. Previously getting text bounds required all the work of laying out the glyphs, which then had to be repeated for drawing. With GlyphLayout, the work is only done once. Each GlyphRun has `Array<Glyph>` and a `FloatArray` for the positions.\r\n1. Next comes BitmapFontCache. This class now has an `Array<GlyphLayout>` and its job is to store the vertex data for rendering the glyphs in those GlyphLayouts. Most of BitmapFontCache was left intact, eg it still can render from multiple texture regions.\r\n\r\nThere are a number of relatively small API breaking changes:\r\n\r\n1. The BitmapFontCache `setText`, `setMultilineText`, `setWrappedText`, and similar `addXxx` methods are replaced by `setText` and `addText`. The number of overloads was kept reasonable. The same happened to the BitmapFont draw methods, which delegate to BitmapFontCache. These methods all return GlyphLayout instead of TextBounds.\r\n1. BitmapFont.TextBounds is deprecated. I should have never added it and just used Vector2. Now, GlyphLayout has `width` and `height` and replaces TextBounds.\r\n1. BitmapFont.HAlignment is gone. Align is used instead.\r\n1. `markupEnabled` was moved to BitmapFontData.\r\n1. BitmapFont `getBounds` and related methods were mostly removed, with the single most commonly used method deprecated. GlyphLayout should be used directly to avoid computing glyphs multiple times.\r\n1. BitmapFont `computeGlyphAdvancesAndPositions` and `computeVisibleGlyphs` are deprecated and should be removed because they assume a 1:1 mapping of characters to glyphs. GlyphLayout can be used instead, which provides each glyph position. ~~I haven't made this change since it affects TextField and friends, but I will once this gets merged.~~ Now done.\r\n\r\nFeedback on these changes is welcome. I've used the gdx-tests to verify things are still working. I also have updated Spine to use this, which is relatively complex real world usage. The font APIs are widely used so it's important we get this right. Now is a good time to break the API further if we need to."},"comment":{"url":"https://api.github.com/repos/libgdx/libgdx/issues/comments/84670391","html_url":"https://github.com/libgdx/libgdx/pull/2955#issuecomment-84670391","issue_url":"https://api.github.com/repos/libgdx/libgdx/issues/2955","id":84670391,"user":{"login":"nooone","id":5896510,"avatar_url":"https://avatars.githubusercontent.com/u/5896510?v=3","gravatar_id":"","url":"https://api.github.com/users/nooone","html_url":"https://github.com/nooone","followers_url":"https://api.github.com/users/nooone/followers","following_url":"https://api.github.com/users/nooone/following{/other_user}","gists_url":"https://api.github.com/users/nooone/gists{/gist_id}","starred_url":"https://api.github.com/users/nooone/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/nooone/subscriptions","organizations_url":"https://api.github.com/users/nooone/orgs","repos_url":"https://api.github.com/users/nooone/repos","events_url":"https://api.github.com/users/nooone/events{/privacy}","received_events_url":"https://api.github.com/users/nooone/received_events","type":"User","site_admin":false},"created_at":"2015-03-22T18:26:03Z","updated_at":"2015-03-22T18:26:03Z","body":"Really nice PR!\r\n\r\n> Let's make a \"break all yo shit\" release! :hurtrealbad:\r\nBitmapFont still has a `@Deprecated getBounds(...)`  though. Maybe let's get rid of that as well then?"}}