OSDN Git Service

[changed] BitmapFont to use cap height as origin rather than baseline. Named methods...
authornathan.sweet <nathan.sweet@6c4fd544-2939-11df-bb46-9574ba5d0bfa>
Fri, 26 Nov 2010 07:46:33 +0000 (07:46 +0000)
committernathan.sweet <nathan.sweet@6c4fd544-2939-11df-bb46-9574ba5d0bfa>
Fri, 26 Nov 2010 07:46:33 +0000 (07:46 +0000)
[added] BitmapFontAlignmentTest.

extensions/twl/gdx-twl/src/com/badlogic/gdx/twl/renderer/GdxFont.java
gdx/src/com/badlogic/gdx/graphics/BitmapFont.java
gdx/src/com/badlogic/gdx/graphics/BitmapFontCache.java
gdx/src/com/badlogic/gdx/graphics/particles/ParticleEffect.java
gdx/src/com/badlogic/gdx/graphics/particles/ParticleEmitter.java
tests/gdx-tests/src/com/badlogic/gdx/tests/BitmapFontAlignmentTest.java [new file with mode: 0644]
tests/gdx-tests/src/com/badlogic/gdx/tests/BitmapFontFlipTest.java
tests/gdx-tests/src/com/badlogic/gdx/tests/BitmapFontTest.java
tests/gdx-tests/src/com/badlogic/gdx/tests/FilesTest.java
tests/gdx-tests/src/com/badlogic/gdx/tests/utils/GdxTests.java

index d8b3b04..7bbde5f 100644 (file)
@@ -54,7 +54,7 @@ class GdxFont implements Font {
        public GdxFont (GdxRenderer renderer, BitmapFont bitmapFont, Map<String, String> params, Collection<FontParameter> condParams) {
                this.bitmapFont = bitmapFont;
                this.renderer = renderer;
-               yOffset = bitmapFont.getLineHeight() - bitmapFont.getBaseLine();
+               yOffset = bitmapFont.getLineHeight() - bitmapFont.getCapHeight() - bitmapFont.getBaseLine();
 
                ArrayList<FontState> states = new ArrayList<FontState>();
                for (FontParameter p : condParams) {
@@ -75,7 +75,7 @@ class GdxFont implements Font {
                x += fontState.offsetX;
                y += fontState.offsetY + yOffset;
                com.badlogic.gdx.graphics.Color color = renderer.getColor(fontState.color);
-               return bitmapFont.draw(renderer.spriteBatch, str, x, y, color, start, end);
+               return (int)bitmapFont.draw(renderer.spriteBatch, str, x, y, color, start, end);
        }
 
        public int drawMultiLineText (AnimationState as, int x, int y, CharSequence str, int width,
@@ -84,7 +84,7 @@ class GdxFont implements Font {
                x += fontState.offsetX;
                y += fontState.offsetY + yOffset;
                com.badlogic.gdx.graphics.Color color = renderer.getColor(fontState.color);
-               return bitmapFont.drawMultiLineText(renderer.spriteBatch, str, x, y, color, width, gdxAlignment[align.ordinal()]);
+               return bitmapFont.drawMultiLine(renderer.spriteBatch, str, x, y, color, width, gdxAlignment[align.ordinal()]);
        }
 
        public FontCache cacheText (FontCache cache, CharSequence str) {
@@ -130,15 +130,15 @@ class GdxFont implements Font {
        }
 
        public int computeMultiLineTextWidth (CharSequence str) {
-               return bitmapFont.computeMultiLineTextWidth(str);
+               return bitmapFont.getMultiLineBounds(str).width;
        }
 
        public int computeTextWidth (CharSequence str) {
-               return bitmapFont.computeTextWidth(str);
+               return bitmapFont.getBounds(str).width;
        }
 
        public int computeTextWidth (CharSequence str, int start, int end) {
-               return bitmapFont.computeTextWidth(str, start, end);
+               return bitmapFont.getBounds(str, start, end).width;
        }
 
        public int computeVisibleGlpyhs (CharSequence str, int start, int end, int width) {
index 7ba3db7..b2c2c88 100644 (file)
@@ -37,596 +37,557 @@ import java.io.InputStreamReader;
 import java.util.StringTokenizer;\r
 \r
 /**\r
- * Loads and renders AngleCode BMFont files. The bitmap font consists of 2\r
- * files: the .fnt file which must be saved with text encoding (not xml or\r
- * binary!) and the bitmap file holding the glyphs, usually in .png format.<br>\r
+ * Loads and renders AngleCode BMFont files. The bitmap font consists of 2 files: the .fnt file which must be saved with text\r
+ * encoding (not xml or binary!) and the bitmap file holding the glyphs, usually in .png format.<br>\r
  * <br>\r
  * This implementation currently only supports a single glyph page.<br>\r
  * <br>\r
- * To draw text with this class you need to call one of the draw() methods\r
- * together with a {@link SpriteBatch}. The SpriteBatch must be in rendering\r
- * mode, that is, {@link SpriteBatch#begin()} must have been called before\r
- * drawing.<br>\r
+ * To draw text with this class you need to call one of the draw() methods together with a {@link SpriteBatch}. The SpriteBatch\r
+ * must be in rendering mode, that is, {@link SpriteBatch#begin()} must have been called before drawing.<br>\r
  * <br>\r
- * Text can be cached in a {@link BitmapFontCache} for faster rendering of static \r
- * text. <br>\r
+ * Text can be cached in a {@link BitmapFontCache} for faster rendering of static text. <br>\r
  * <br>\r
- * A BitmapFont loaded from a file is managed. {@link #dispose()} must be called to \r
- * free the backing texture when no longer needed. A BitmapFont loaded using a \r
- * sprite is managed if the sprite's texture is managed. Disposing the BitmapFont\r
- * disposes the sprite's texture, which may not be desirable if the texture is still\r
- * being used elsewhere.<br>\r
+ * A BitmapFont loaded from a file is managed. {@link #dispose()} must be called to free the backing texture when no longer\r
+ * needed. A BitmapFont loaded using a sprite is managed if the sprite's texture is managed. Disposing the BitmapFont disposes the\r
+ * sprite's texture, which may not be desirable if the texture is still being used elsewhere.<br>\r
  * <br>\r
- * The code is heavily based on Matthias Mann's TWL BitmapFont class. Thanks for\r
- * sharing, Matthias! :)\r
- *\r
+ * The code is heavily based on Matthias Mann's TWL BitmapFont class. Thanks for sharing, Matthias! :)\r
  * @author Nathan Sweet <misc@n4te.com>\r
  * @author Matthias Mann\r
  */\r
 public class BitmapFont {\r
-    private static final int LOG2_PAGE_SIZE = 9;\r
-    private static final int PAGE_SIZE = 1 << LOG2_PAGE_SIZE;\r
-    private static final int PAGES = 0x10000 / PAGE_SIZE;\r
-\r
-    Sprite sprite;\r
-    int lineHeight;\r
-    int yOffset;\r
-    int down;\r
-\r
-    private Glyph[][] glyphs = new Glyph[PAGES][];\r
-    private int baseLine;\r
-    private int spaceWidth;\r
-    private int xHeight;\r
-    private int capHeight;\r
-\r
-    /**\r
-     * Creates a new BitmapFont using the default 15pt Arial font included in\r
-     * the gdx jar file. This is here to get you up and running quickly.\r
-     */\r
-    public BitmapFont() {\r
+       private static final int LOG2_PAGE_SIZE = 9;\r
+       private static final int PAGE_SIZE = 1 << LOG2_PAGE_SIZE;\r
+       private static final int PAGES = 0x10000 / PAGE_SIZE;\r
+\r
+       Sprite sprite;\r
+       int lineHeight;\r
+       int capHeight;\r
+       int yOffset;\r
+       int down;\r
+\r
+       private final Glyph[][] glyphs = new Glyph[PAGES][];\r
+       private int baseLine;\r
+       private int spaceWidth;\r
+       private int xHeight;\r
+       private final TextBounds textBounds = new TextBounds();\r
+\r
+       /**\r
+        * Creates a new BitmapFont using the default 15pt Arial font included in the gdx jar file. This is here to get you up and\r
+        * running quickly.\r
+        */\r
+       public BitmapFont () {\r
                this(Gdx.files.classpath("com/badlogic/gdx/utils/arial-15.fnt"),\r
                        Gdx.files.classpath("com/badlogic/gdx/utils/arial-15.png"), false);\r
-    }\r
+       }\r
 \r
        /**\r
         * Creates a new BitmapFont with the glyphs relative to the specified sprite.\r
         * @param sprite The sprite containing the glyphs. It must NOT be flipped.\r
         * @param flip If true, the glyphs will be flipped for use with a perspective where 0,0 is the upper left corner.\r
         */\r
-    public BitmapFont(FileHandle fontFile, Sprite sprite, boolean flip) {\r
-        init(fontFile, sprite, flip);\r
-    }\r
-\r
-    /**\r
-     * Creates a new BitmapFont instance based on a .fnt file and an image file\r
-     * holding the page with glyphs. Currently only supports single page\r
-     * AngleCode fonts.\r
-     *\r
-     * @param fontFile  The font file\r
-     * @param imageFile The image file\r
-     * @param flip      If true, the glyphs will be flipped for use with a perspective\r
-     *                  where 0,0 is the upper left corner.\r
-     */\r
-    public BitmapFont(FileHandle fontFile, FileHandle imageFile, boolean flip) {\r
-        sprite = new Sprite(Gdx.graphics.newTexture(imageFile, TextureFilter.Linear,\r
-                TextureFilter.Linear, TextureWrap.ClampToEdge,\r
-                TextureWrap.ClampToEdge));\r
-        init(fontFile, sprite, flip);\r
-    }\r
-\r
-\r
-    private void init(FileHandle fontFile, Sprite sprite, boolean flip) {\r
-        this.sprite = sprite;\r
-        float invTexWidth = 1.0f / sprite.getTexture().getWidth();\r
-        float invTexHeight = 1.0f / sprite.getTexture().getHeight();\r
-        float uSprite = sprite.getTextureRegionX();\r
-        float vSprite = sprite.getTextureRegionY();\r
-        float u2Sprite = uSprite + sprite.getTextureRegionWidth();\r
-        float v2Sprite = vSprite + sprite.getTextureRegionHeight();\r
-\r
-        BufferedReader reader = new BufferedReader(new InputStreamReader(fontFile.read()), 512);\r
-        try {\r
-            reader.readLine(); // info\r
-\r
-            String[] common = reader.readLine().split(" ", 4);\r
-            if (common.length < 4)\r
-                throw new GdxRuntimeException("Invalid font file: " + fontFile);\r
-\r
-            if (!common[1].startsWith("lineHeight="))\r
-                throw new GdxRuntimeException("Invalid font file: " + fontFile);\r
-            lineHeight = Integer.parseInt(common[1].substring(11));\r
-\r
-            if (!common[2].startsWith("base="))\r
-                throw new GdxRuntimeException("Invalid font file: " + fontFile);\r
-            baseLine = Integer.parseInt(common[2].substring(5));\r
-\r
-            reader.readLine(); // page\r
-            while (true) {\r
-                String line = reader.readLine();\r
-                if (line == null)\r
-                    break;\r
-                if (line.startsWith("kernings "))\r
-                    break;\r
-                if (!line.startsWith("char "))\r
-                    continue;\r
-\r
-                Glyph glyph = new Glyph();\r
-\r
-                StringTokenizer tokens = new StringTokenizer(line, " =");\r
-                tokens.nextToken();\r
-                tokens.nextToken();\r
-                int ch = Integer.parseInt(tokens.nextToken());\r
-                if (ch <= Character.MAX_VALUE) {\r
-                    Glyph[] page = glyphs[ch / PAGE_SIZE];\r
-                    if (page == null)\r
-                        glyphs[ch / PAGE_SIZE] = page = new Glyph[PAGE_SIZE];\r
-                    page[ch & (PAGE_SIZE - 1)] = glyph;\r
-                } else\r
-                    continue;\r
-                tokens.nextToken();\r
-                float srcX = Integer.parseInt(tokens.nextToken());\r
-                tokens.nextToken();\r
-                float srcY = Integer.parseInt(tokens.nextToken());\r
-                tokens.nextToken();\r
-                glyph.width = (Integer.parseInt(tokens.nextToken()));\r
-                tokens.nextToken();\r
-                glyph.height = Integer.parseInt(tokens.nextToken());\r
-                tokens.nextToken();\r
-                glyph.xoffset = Integer.parseInt(tokens.nextToken());\r
-                tokens.nextToken();\r
-                if (flip)\r
-                    glyph.yoffset = Integer.parseInt(tokens.nextToken());\r
-                else\r
-                    glyph.yoffset = -(glyph.height + Integer.parseInt(tokens\r
-                            .nextToken()));\r
-                tokens.nextToken();\r
-                glyph.xadvance = Integer.parseInt(tokens.nextToken());\r
-\r
-                glyph.u = uSprite + srcX * invTexWidth;\r
-                glyph.u2 = uSprite + (srcX + glyph.width) * invTexWidth;\r
-                if (flip) {\r
-                    glyph.v = vSprite + srcY * invTexHeight;\r
-                    glyph.v2 = vSprite + (srcY + glyph.height) * invTexHeight;\r
-                } else {\r
-                    glyph.v2 = vSprite + srcY * invTexHeight;\r
-                    glyph.v = vSprite + (srcY + glyph.height) * invTexHeight;\r
-                }\r
-            }\r
-\r
-            while (true) {\r
-                String line = reader.readLine();\r
-                if (line == null)\r
-                    break;\r
-                if (!line.startsWith("kerning "))\r
-                    break;\r
-\r
-                StringTokenizer tokens = new StringTokenizer(line, " =");\r
-                tokens.nextToken();\r
-                tokens.nextToken();\r
-                int first = Integer.parseInt(tokens.nextToken());\r
-                tokens.nextToken();\r
-                int second = Integer.parseInt(tokens.nextToken());\r
-                if (first < 0 || first > Character.MAX_VALUE || second < 0\r
-                        || second > Character.MAX_VALUE)\r
-                    continue;\r
-                Glyph glyph = getGlyph((char) first);\r
-                tokens.nextToken();\r
-                int amount = Integer.parseInt(tokens.nextToken());\r
-                glyph.setKerning(second, amount);\r
-            }\r
-\r
-            Glyph g = getGlyph(' ');\r
-            spaceWidth = (g != null) ? g.xadvance + g.width : 1;\r
-\r
-            g = getGlyph('x');\r
-            xHeight = g != null ? g.height : 1;\r
-\r
-            g = getGlyph('M');\r
-            capHeight = g != null ? g.height : 1;\r
-\r
-            yOffset = flip ? -baseLine : baseLine;\r
-            down = flip ? lineHeight : -lineHeight;\r
-        } catch (Exception ex) {\r
-            throw new GdxRuntimeException("Error loading font file: "\r
-                    + fontFile, ex);\r
-        } finally {\r
-            try {\r
-                reader.close();\r
-            } catch (IOException ignored) {\r
-            }\r
-        }\r
-    }\r
-\r
-    Glyph getGlyph(char ch) {\r
-        Glyph[] page = glyphs[ch / PAGE_SIZE];\r
-        if (page != null)\r
-            return page[ch & (PAGE_SIZE - 1)];\r
-        return null;\r
-    }\r
-\r
-    /**\r
-     * Draws the given string at the given position with the given color. You\r
-     * can only call this between {@link SpriteBatch#begin()}/\r
-     * {@link SpriteBatch#end()}.\r
-     *\r
-     * @param spriteBatch The {@link SpriteBatch} to use\r
-     * @param str         The string\r
-     * @param x           The x position of the left most character\r
-     * @param y           The y position of the left most character's top left corner\r
-     * @param color       The color\r
-     * @return the width of the rendered string\r
-     */\r
-    public int draw(SpriteBatch spriteBatch, CharSequence str, int x, int y,\r
-                    Color color) {\r
-        return draw(spriteBatch, str, x, y, color, 0, str.length());\r
-    }\r
-\r
-    /**\r
-     * Draws the given string at the given position with the given color. You\r
-     * can only call this between {@link SpriteBatch#begin()}/\r
-     * {@link SpriteBatch#end()}.\r
-     *\r
-     * @param spriteBatch The {@link SpriteBatch} to use\r
-     * @param str         The string\r
-     * @param x           The x position of the left most character\r
-     * @param y           The y position of the left most character's top left corner\r
-     * @param tint        The color\r
-     * @param start       the first character of the string to draw\r
-     * @param end         the last character of the string to draw\r
-     * @return the width of the rendered string\r
-     */\r
-    public int draw(SpriteBatch spriteBatch, CharSequence str, int x, int y,\r
-                    Color tint, int start, int end) {\r
-        final Texture texture = sprite.getTexture();\r
-        final float color = tint.toFloatBits();\r
-        y += yOffset;\r
-        int startX = x;\r
-        Glyph lastGlyph = null;\r
-        while (start < end) {\r
-            lastGlyph = getGlyph(str.charAt(start++));\r
-            if (lastGlyph != null) {\r
-                spriteBatch.draw(texture, x + lastGlyph.xoffset, y\r
-                        + lastGlyph.yoffset, lastGlyph.width, lastGlyph.height,\r
-                        lastGlyph.u, lastGlyph.v, lastGlyph.u2, lastGlyph.v2,\r
-                        color);\r
-                x += lastGlyph.xadvance;\r
-                break;\r
-            }\r
-        }\r
-        while (start < end) {\r
-            char ch = str.charAt(start++);\r
-            Glyph g = getGlyph(ch);\r
-            if (g == null)\r
-                continue;\r
-            x += lastGlyph.getKerning(ch);\r
-            lastGlyph = g;\r
-            spriteBatch\r
-                    .draw(texture, x + lastGlyph.xoffset,\r
-                            y + lastGlyph.yoffset, lastGlyph.width,\r
-                            lastGlyph.height, lastGlyph.u, lastGlyph.v,\r
-                            lastGlyph.u2, lastGlyph.v2, color);\r
-            x += g.xadvance;\r
-        }\r
-        return x - startX;\r
-    }\r
-\r
-    /**\r
-     * Draws the given string at the given position with the given color. The\r
-     * position coincides with the top left corner of the first line's glyph.\r
-     * This method interprets new lines. You can only call this between\r
-     * {@link SpriteBatch#begin()}/ {@link SpriteBatch#end()}.\r
-     *\r
-     * @param spriteBatch The {@link SpriteBatch} to use\r
-     * @param str         The string\r
-     * @param x           The x position of the left most character of the first line\r
-     * @param y           The y position of the left most character's top left corner of\r
-     *                    the first line\r
-     * @param color       The color\r
-     * @return The height of the rendered string\r
-     */\r
-    public int drawMultiLineText(SpriteBatch spriteBatch, CharSequence str,\r
-                                 int x, int y, Color color) {\r
-        return drawMultiLineText(spriteBatch, str, x, y, color, 0,\r
-                HAlignment.LEFT);\r
-    }\r
-\r
-    /**\r
-     * Draws the given string at the given position with the given color. The\r
-     * position coincides with the top left corner of the first line's glyph.\r
-     * The method interprets new lines. You can only call this between\r
-     * {@link SpriteBatch#begin()}/ {@link SpriteBatch#end()}. <br>\r
-     * <br>\r
-     * You can specify the horizontal alignment of the text with the\r
-     * <code>alignmentWidth</code> and <code>alignment</code> parameters. The\r
-     * first parameter specifies the width of the rectangle the text should be\r
-     * aligned in (x to x + alignmentWidth). The second parameter specifies the\r
-     * alignment itself.\r
-     *\r
-     * @param spriteBatch    The {@link SpriteBatch} to use\r
-     * @param str            The string\r
-     * @param x              The x position of the left most character of the first line\r
-     * @param y              The y position of the left most character's top left corner of\r
-     *                       the first line\r
-     * @param color          The color\r
-     * @param alignmentWidth The alignment width\r
-     * @param alignment      The horizontal alignment\r
-     * @return The height of the multiline text\r
-     */\r
-    public int drawMultiLineText(SpriteBatch spriteBatch, CharSequence str,\r
-                                 int x, int y, Color color, int alignmentWidth, HAlignment alignment) {\r
-        int down = this.down;\r
-        int start = 0;\r
-        int numLines = 0;\r
-        int length = str.length();\r
-        while (start < length) {\r
-            int lineEnd = indexOf(str, '\n', start);\r
-            int xOffset = 0;\r
-            if (alignment != HAlignment.LEFT) {\r
-                int lineWidth = computeTextWidth(str, start, lineEnd);\r
-                xOffset = alignmentWidth - lineWidth;\r
-                if (alignment == HAlignment.CENTER)\r
-                    xOffset /= 2;\r
-            }\r
-            draw(spriteBatch, str, x + xOffset, y, color, start, lineEnd);\r
-            start = lineEnd + 1;\r
-            y += down;\r
-            numLines++;\r
-        }\r
-        return numLines * lineHeight;\r
-    }\r
-\r
-    /**\r
-     * Draws the given string at the given position with the given color. The\r
-     * position coincides with the top left corner of the first line's glyph.\r
-     * This method interprets new lines and causes the text to wrap at spaces\r
-     * based on the given <code>wrapWidth</code>. You can only call this between\r
-     * {@link SpriteBatch#begin()}/ {@link SpriteBatch#end()}.\r
-     *\r
-     * @param spriteBatch The {@link SpriteBatch} to use\r
-     * @param str         The string\r
-     * @param x           The x position of the left most character of the first line\r
-     * @param y           The y position of the left most character's top left corner of\r
-     *                    the first line\r
-     * @param color       The color\r
-     * @param wrapWidth   The wrap width\r
-     * @return the height of the rendered string\r
-     */\r
-    public int drawWrappedText(SpriteBatch spriteBatch, CharSequence str,\r
-                               int x, int y, Color color, int wrapWidth) {\r
-        return drawWrappedText(spriteBatch, str, x, y, color, wrapWidth,\r
-                HAlignment.LEFT);\r
-    }\r
-\r
-    /**\r
-     * Draws the given string at the given position with the given color. The\r
-     * position coincides with the top left corner of the first line's glyph.\r
-     * This method interprets new lines and causes the text to wrap at spaces\r
-     * based on the given <code>wrapWidth</code>. You can only call this between\r
-     * {@link SpriteBatch#begin()}/ {@link SpriteBatch#end()}.<br>\r
-     * <br>\r
-     * You can specify the horizontal alignment of the text within the\r
-     * <code>wrapWidth</code> by using the <code>alignment</code> parameter.\r
-     *\r
-     * @param spriteBatch The {@link SpriteBatch} to use\r
-     * @param str         The string\r
-     * @param x           The x position of the left most character of the first line\r
-     * @param y           The y position of the left most character's top left corner of\r
-     *                    the first line\r
-     * @param color       The color\r
-     * @param wrapWidth   The wrap width\r
-     * @return the height of the rendered string\r
-     */\r
-    public int drawWrappedText(SpriteBatch spriteBatch, CharSequence str,\r
-                               int x, int y, Color color, int wrapWidth, HAlignment alignment) {\r
-        int down = this.down;\r
-        int start = 0;\r
-        int numLines = 0;\r
-        int length = str.length();\r
-        while (start < length) {\r
-            int lineEnd = start\r
-                    + computeVisibleGlpyhs(str, start,\r
-                    indexOf(str, '\n', start), wrapWidth);\r
-            if (lineEnd < length) {\r
-                while (lineEnd > start) {\r
-                    char ch = str.charAt(lineEnd);\r
-                    if (ch == ' ' || ch == '\n')\r
-                        break;\r
-                    lineEnd--;\r
-                }\r
-            }\r
-            if (lineEnd == start)\r
-                lineEnd++;\r
-            int xOffset = 0;\r
-            if (alignment != HAlignment.LEFT) {\r
-                int lineWidth = computeTextWidth(str, start, lineEnd);\r
-                xOffset = wrapWidth - lineWidth;\r
-                if (alignment == HAlignment.CENTER)\r
-                    xOffset /= 2;\r
-            }\r
-            draw(spriteBatch, str, x + xOffset, y, color, start, lineEnd);\r
-            start = lineEnd + 1;\r
-            y += down;\r
-            numLines++;\r
-        }\r
-        return numLines * lineHeight;\r
-    }\r
-\r
-    /**\r
-     * Computes the width of the string.\r
-     *\r
-     * @param str The string\r
-     * @return the width\r
-     */\r
-    public int computeTextWidth(CharSequence str) {\r
-        return computeTextWidth(str, 0, str.length());\r
-    }\r
-\r
-    /**\r
-     * Computes the width of the string.\r
-     *\r
-     * @param str   the string\r
-     * @param start The first character index\r
-     * @param end   The last character index (exclusive)\r
-     * @return The string width\r
-     */\r
-    public int computeTextWidth(CharSequence str, int start, int end) {\r
-        int width = 0;\r
-        Glyph lastGlyph = null;\r
-        while (start < end) {\r
-            lastGlyph = getGlyph(str.charAt(start++));\r
-            if (lastGlyph != null) {\r
-                width = lastGlyph.xadvance;\r
-                break;\r
-            }\r
-        }\r
-        while (start < end) {\r
-            char ch = str.charAt(start++);\r
-            Glyph g = getGlyph(ch);\r
-            if (g != null) {\r
-                width += lastGlyph.getKerning(ch);\r
-                lastGlyph = g;\r
-                width += g.xadvance;\r
-            }\r
-        }\r
-        return width;\r
-    }\r
-\r
-    /**\r
-     * Returns the number of characters that can be rendered given the available\r
-     * width.\r
-     *\r
-     * @param str            The string\r
-     * @param start          The start index of the first character\r
-     * @param end            The index of the last character (exclusive)\r
-     * @param availableWidth the available width\r
-     * @return The number of characters that fit into availableWdith\r
-     */\r
-    public int computeVisibleGlpyhs(CharSequence str, int start, int end,\r
-                                    int availableWidth) {\r
-        int index = start;\r
-        int width = 0;\r
-        Glyph lastGlyph = null;\r
-        for (; index < end; index++) {\r
-            char ch = str.charAt(index);\r
-            Glyph g = getGlyph(ch);\r
-            if (g != null) {\r
-                if (lastGlyph != null)\r
-                    width += lastGlyph.getKerning(ch);\r
-                lastGlyph = g;\r
-                if (width + g.width + g.xoffset > availableWidth)\r
-                    break;\r
-                width += g.xadvance;\r
-            }\r
-        }\r
-        return index - start;\r
-    }\r
-\r
-    /**\r
-     * Computes the maximum width of the string, respecting newlines.\r
-     *\r
-     * @param str The string\r
-     * @return The maximum width\r
-     */\r
-    public int computeMultiLineTextWidth(CharSequence str) {\r
-        int start = 0;\r
-        int width = 0;\r
-        int length = str.length();\r
-        while (start < length) {\r
-            int lineEnd = indexOf(str, '\n', start);\r
-            int lineWidth = computeTextWidth(str, start, lineEnd);\r
-            width = Math.max(width, lineWidth);\r
-            start = lineEnd + 1;\r
-        }\r
-        return width;\r
-    }\r
-\r
-    /**\r
-     * @return The glyph sprite\r
-     */\r
-    public Sprite getSprite() {\r
-        return sprite;\r
-    }\r
-\r
-    /**\r
-     * @return The baseline offset, which is the distance from the drawing\r
-     *         position to the line that most glyphs sit on\r
-     */\r
-    public int getBaseLine() {\r
-        return baseLine;\r
-    }\r
-\r
-    /**\r
-     * @return The line height, which is the distance from one line of text to\r
-     *         the next\r
-     */\r
-    public int getLineHeight() {\r
-        return lineHeight;\r
-    }\r
-\r
-    /**\r
-     * @return The width of the space character\r
-     */\r
-    public int getSpaceWidth() {\r
-        return spaceWidth;\r
-    }\r
-\r
-    /**\r
-     * @return The x-height, which is the typical height of lowercase characters\r
-     */\r
-    public int getXHeight() {\r
-        return xHeight;\r
-    }\r
-\r
-    /**\r
-     * @return The cap height, which is the typical height of uppercase\r
-     *         characters\r
-     */\r
-    public int getCapHeight() {\r
-        return capHeight;\r
-    }\r
-\r
-    /**\r
-     * Disposes the texture used by this BitmapFont's sprite.\r
-     */\r
-    public void dispose() {\r
-        sprite.getTexture().dispose();\r
-    }\r
-\r
-    static class Glyph {\r
-        int width, height;\r
-        float u, v, u2, v2;\r
-        int xoffset, yoffset;\r
-        int xadvance;\r
-        byte[][] kerning;\r
-\r
-        int getKerning(char ch) {\r
-            if (kerning != null) {\r
-                byte[] page = kerning[ch >>> LOG2_PAGE_SIZE];\r
-                if (page != null)\r
-                    return page[ch & (PAGE_SIZE - 1)];\r
-            }\r
-            return 0;\r
-        }\r
-\r
-        void setKerning(int ch, int value) {\r
-            if (kerning == null)\r
-                kerning = new byte[PAGES][];\r
-            byte[] page = kerning[ch >>> LOG2_PAGE_SIZE];\r
-            if (page == null)\r
-                kerning[ch >>> LOG2_PAGE_SIZE] = page = new byte[PAGE_SIZE];\r
-            page[ch & (PAGE_SIZE - 1)] = (byte) value;\r
-        }\r
-    }\r
-\r
-    static int indexOf(CharSequence text, char ch, int start) {\r
-        final int n = text.length();\r
-        for (; start < n; start++)\r
-            if (text.charAt(start) == ch)\r
-                return start;\r
-        return n;\r
-    }\r
-\r
-    static public enum HAlignment {\r
-        LEFT, CENTER, RIGHT\r
-    }\r
+       public BitmapFont (FileHandle fontFile, Sprite sprite, boolean flip) {\r
+               init(fontFile, sprite, flip);\r
+       }\r
+\r
+       /**\r
+        * Creates a new BitmapFont instance based on a .fnt file and an image file holding the page with glyphs. Currently only\r
+        * supports single page AngleCode fonts.\r
+        * @param fontFile The font file\r
+        * @param imageFile The image file\r
+        * @param flip If true, the glyphs will be flipped for use with a perspective where 0,0 is the upper left corner.\r
+        */\r
+       public BitmapFont (FileHandle fontFile, FileHandle imageFile, boolean flip) {\r
+               sprite = new Sprite(Gdx.graphics.newTexture(imageFile, TextureFilter.Linear, TextureFilter.Linear, TextureWrap.ClampToEdge,\r
+                       TextureWrap.ClampToEdge));\r
+               init(fontFile, sprite, flip);\r
+       }\r
+\r
+       private void init (FileHandle fontFile, Sprite sprite, boolean flip) {\r
+               this.sprite = sprite;\r
+               float invTexWidth = 1.0f / sprite.getTexture().getWidth();\r
+               float invTexHeight = 1.0f / sprite.getTexture().getHeight();\r
+               float uSprite = sprite.getTextureRegionX();\r
+               float vSprite = sprite.getTextureRegionY();\r
+               float u2Sprite = uSprite + sprite.getTextureRegionWidth();\r
+               float v2Sprite = vSprite + sprite.getTextureRegionHeight();\r
+\r
+               BufferedReader reader = new BufferedReader(new InputStreamReader(fontFile.read()), 512);\r
+               try {\r
+                       reader.readLine(); // info\r
+\r
+                       String[] common = reader.readLine().split(" ", 4);\r
+                       if (common.length < 4) throw new GdxRuntimeException("Invalid font file: " + fontFile);\r
+\r
+                       if (!common[1].startsWith("lineHeight=")) throw new GdxRuntimeException("Invalid font file: " + fontFile);\r
+                       lineHeight = Integer.parseInt(common[1].substring(11));\r
+\r
+                       if (!common[2].startsWith("base=")) throw new GdxRuntimeException("Invalid font file: " + fontFile);\r
+                       baseLine = Integer.parseInt(common[2].substring(5));\r
+\r
+                       reader.readLine(); // page\r
+                       while (true) {\r
+                               String line = reader.readLine();\r
+                               if (line == null) break;\r
+                               if (line.startsWith("kernings ")) break;\r
+                               if (!line.startsWith("char ")) continue;\r
+\r
+                               Glyph glyph = new Glyph();\r
+\r
+                               StringTokenizer tokens = new StringTokenizer(line, " =");\r
+                               tokens.nextToken();\r
+                               tokens.nextToken();\r
+                               int ch = Integer.parseInt(tokens.nextToken());\r
+                               if (ch <= Character.MAX_VALUE) {\r
+                                       Glyph[] page = glyphs[ch / PAGE_SIZE];\r
+                                       if (page == null) glyphs[ch / PAGE_SIZE] = page = new Glyph[PAGE_SIZE];\r
+                                       page[ch & (PAGE_SIZE - 1)] = glyph;\r
+                               } else\r
+                                       continue;\r
+                               tokens.nextToken();\r
+                               float srcX = Integer.parseInt(tokens.nextToken());\r
+                               tokens.nextToken();\r
+                               float srcY = Integer.parseInt(tokens.nextToken());\r
+                               tokens.nextToken();\r
+                               glyph.width = (Integer.parseInt(tokens.nextToken()));\r
+                               tokens.nextToken();\r
+                               glyph.height = Integer.parseInt(tokens.nextToken());\r
+                               tokens.nextToken();\r
+                               glyph.xoffset = Integer.parseInt(tokens.nextToken());\r
+                               tokens.nextToken();\r
+                               if (flip)\r
+                                       glyph.yoffset = Integer.parseInt(tokens.nextToken());\r
+                               else\r
+                                       glyph.yoffset = -(glyph.height + Integer.parseInt(tokens.nextToken()));\r
+                               tokens.nextToken();\r
+                               glyph.xadvance = Integer.parseInt(tokens.nextToken());\r
+\r
+                               glyph.u = uSprite + srcX * invTexWidth;\r
+                               glyph.u2 = uSprite + (srcX + glyph.width) * invTexWidth;\r
+                               if (flip) {\r
+                                       glyph.v = vSprite + srcY * invTexHeight;\r
+                                       glyph.v2 = vSprite + (srcY + glyph.height) * invTexHeight;\r
+                               } else {\r
+                                       glyph.v2 = vSprite + srcY * invTexHeight;\r
+                                       glyph.v = vSprite + (srcY + glyph.height) * invTexHeight;\r
+                               }\r
+                       }\r
+\r
+                       while (true) {\r
+                               String line = reader.readLine();\r
+                               if (line == null) break;\r
+                               if (!line.startsWith("kerning ")) break;\r
+\r
+                               StringTokenizer tokens = new StringTokenizer(line, " =");\r
+                               tokens.nextToken();\r
+                               tokens.nextToken();\r
+                               int first = Integer.parseInt(tokens.nextToken());\r
+                               tokens.nextToken();\r
+                               int second = Integer.parseInt(tokens.nextToken());\r
+                               if (first < 0 || first > Character.MAX_VALUE || second < 0 || second > Character.MAX_VALUE) continue;\r
+                               Glyph glyph = getGlyph((char)first);\r
+                               tokens.nextToken();\r
+                               int amount = Integer.parseInt(tokens.nextToken());\r
+                               glyph.setKerning(second, amount);\r
+                       }\r
+\r
+                       Glyph g = getGlyph(' ');\r
+                       spaceWidth = (g != null) ? g.xadvance + g.width : 1;\r
+\r
+                       g = getGlyph('x');\r
+                       xHeight = g != null ? g.height : 1;\r
+\r
+                       g = getGlyph('M');\r
+                       capHeight = g != null ? g.height : 1;\r
+\r
+                       yOffset = baseLine - capHeight;\r
+                       down = -lineHeight;\r
+                       if (flip) {\r
+                               yOffset = -yOffset;\r
+                               down = -down;\r
+                       }\r
+               } catch (Exception ex) {\r
+                       throw new GdxRuntimeException("Error loading font file: " + fontFile, ex);\r
+               } finally {\r
+                       try {\r
+                               reader.close();\r
+                       } catch (IOException ignored) {\r
+                       }\r
+               }\r
+       }\r
+\r
+       Glyph getGlyph (char ch) {\r
+               Glyph[] page = glyphs[ch / PAGE_SIZE];\r
+               if (page != null) return page[ch & (PAGE_SIZE - 1)];\r
+               return null;\r
+       }\r
+\r
+       /**\r
+        * Draws the given string at the given position with the given color. You can only call this between\r
+        * {@link SpriteBatch#begin()}/ {@link SpriteBatch#end()}.\r
+        * @param spriteBatch The {@link SpriteBatch} to use\r
+        * @param str The string\r
+        * @param x The x position of the left most character\r
+        * @param y The y position of the left most character's top left corner\r
+        * @param color The color\r
+        * @return the width of the rendered string\r
+        */\r
+       public int draw (SpriteBatch spriteBatch, CharSequence str, float x, float y, Color color) {\r
+               return draw(spriteBatch, str, x, y, color, 0, str.length());\r
+       }\r
+\r
+       /**\r
+        * Draws the given string at the given position with the given color. You can only call this between\r
+        * {@link SpriteBatch#begin()}/ {@link SpriteBatch#end()}.\r
+        * @param spriteBatch The {@link SpriteBatch} to use\r
+        * @param str The string\r
+        * @param x The x position of the left most character\r
+        * @param y The y position of the left most character's top left corner\r
+        * @param tint The color\r
+        * @param start the first character of the string to draw\r
+        * @param end the last character of the string to draw\r
+        * @return the width of the rendered string\r
+        */\r
+       public int draw (SpriteBatch spriteBatch, CharSequence str, float x, float y, Color tint, int start, int end) {\r
+               final Texture texture = sprite.getTexture();\r
+               final float color = tint.toFloatBits();\r
+               y += yOffset;\r
+               float startX = x;\r
+               Glyph lastGlyph = null;\r
+               while (start < end) {\r
+                       lastGlyph = getGlyph(str.charAt(start++));\r
+                       if (lastGlyph != null) {\r
+                               spriteBatch.draw(texture, x + lastGlyph.xoffset, y + lastGlyph.yoffset, lastGlyph.width, lastGlyph.height,\r
+                                       lastGlyph.u, lastGlyph.v, lastGlyph.u2, lastGlyph.v2, color);\r
+                               x += lastGlyph.xadvance;\r
+                               break;\r
+                       }\r
+               }\r
+               while (start < end) {\r
+                       char ch = str.charAt(start++);\r
+                       Glyph g = getGlyph(ch);\r
+                       if (g == null) continue;\r
+                       x += lastGlyph.getKerning(ch);\r
+                       lastGlyph = g;\r
+                       spriteBatch.draw(texture, x + lastGlyph.xoffset, y + lastGlyph.yoffset, lastGlyph.width, lastGlyph.height, lastGlyph.u,\r
+                               lastGlyph.v, lastGlyph.u2, lastGlyph.v2, color);\r
+                       x += g.xadvance;\r
+               }\r
+               return (int)(x - startX);\r
+       }\r
+\r
+       /**\r
+        * Draws the given string at the given position with the given color. The position coincides with the top left corner of the\r
+        * first line's glyph. This method interprets new lines. You can only call this between {@link SpriteBatch#begin()}/\r
+        * {@link SpriteBatch#end()}.\r
+        * @param spriteBatch The {@link SpriteBatch} to use\r
+        * @param str The string\r
+        * @param x The x position of the left most character of the first line\r
+        * @param y The y position of the left most character's top left corner of the first line\r
+        * @param color The color\r
+        * @return The height of the rendered string\r
+        */\r
+       public int drawMultiLine (SpriteBatch spriteBatch, CharSequence str, float x, float y, Color color) {\r
+               return drawMultiLine(spriteBatch, str, x, y, color, 0, HAlignment.LEFT);\r
+       }\r
+\r
+       /**\r
+        * Draws the given string at the given position with the given color. The position coincides with the top left corner of the\r
+        * first line's glyph. The method interprets new lines. You can only call this between {@link SpriteBatch#begin()}/\r
+        * {@link SpriteBatch#end()}. <br>\r
+        * <br>\r
+        * You can specify the horizontal alignment of the text with the <code>alignmentWidth</code> and <code>alignment</code>\r
+        * parameters. The first parameter specifies the width of the rectangle the text should be aligned in (x to x +\r
+        * alignmentWidth). The second parameter specifies the alignment itself.\r
+        * @param spriteBatch The {@link SpriteBatch} to use\r
+        * @param str The string\r
+        * @param x The x position of the left most character of the first line\r
+        * @param y The y position of the left most character's top left corner of the first line\r
+        * @param color The color\r
+        * @param alignmentWidth The alignment width\r
+        * @param alignment The horizontal alignment\r
+        * @return The height of the multiline text\r
+        */\r
+       public int drawMultiLine (SpriteBatch spriteBatch, CharSequence str, float x, float y, Color color, float alignmentWidth,\r
+               HAlignment alignment) {\r
+               int down = this.down;\r
+               int start = 0;\r
+               int numLines = 0;\r
+               int length = str.length();\r
+               while (start < length) {\r
+                       int lineEnd = indexOf(str, '\n', start);\r
+                       float xOffset = 0;\r
+                       if (alignment != HAlignment.LEFT) {\r
+                               int lineWidth = getBounds(str, start, lineEnd).width;\r
+                               xOffset = alignmentWidth - lineWidth;\r
+                               if (alignment == HAlignment.CENTER) xOffset /= 2;\r
+                       }\r
+                       draw(spriteBatch, str, x + xOffset, y, color, start, lineEnd);\r
+                       start = lineEnd + 1;\r
+                       y += down;\r
+                       numLines++;\r
+               }\r
+               return capHeight + (numLines - 1) * lineHeight;\r
+       }\r
+\r
+       /**\r
+        * Draws the given string at the given position with the given color. The position coincides with the top left corner of the\r
+        * first line's glyph. This method interprets new lines and causes the text to wrap at spaces based on the given\r
+        * <code>wrapWidth</code>. You can only call this between {@link SpriteBatch#begin()}/ {@link SpriteBatch#end()}.\r
+        * @param spriteBatch The {@link SpriteBatch} to use\r
+        * @param str The string\r
+        * @param x The x position of the left most character of the first line\r
+        * @param y The y position of the left most character's top left corner of the first line\r
+        * @param color The color\r
+        * @param wrapWidth The wrap width\r
+        * @return the height of the rendered string\r
+        */\r
+       public int drawWrapped (SpriteBatch spriteBatch, CharSequence str, float x, float y, Color color, float wrapWidth) {\r
+               return drawWrapped(spriteBatch, str, x, y, color, wrapWidth, HAlignment.LEFT);\r
+       }\r
+\r
+       /**\r
+        * Draws the given string at the given position with the given color. The position coincides with the top left corner of the\r
+        * first line's glyph. This method interprets new lines and causes the text to wrap at spaces based on the given\r
+        * <code>wrapWidth</code>. You can only call this between {@link SpriteBatch#begin()}/ {@link SpriteBatch#end()}.<br>\r
+        * <br>\r
+        * You can specify the horizontal alignment of the text within the <code>wrapWidth</code> by using the <code>alignment</code>\r
+        * parameter.\r
+        * @param spriteBatch The {@link SpriteBatch} to use\r
+        * @param str The string\r
+        * @param x The x position of the left most character of the first line\r
+        * @param y The y position of the left most character's top left corner of the first line\r
+        * @param color The color\r
+        * @param wrapWidth The wrap width\r
+        * @return the height of the rendered string\r
+        */\r
+       public int drawWrapped (SpriteBatch spriteBatch, CharSequence str, float x, float y, Color color, float wrapWidth,\r
+               HAlignment alignment) {\r
+               int down = this.down;\r
+               int start = 0;\r
+               int numLines = 0;\r
+               int length = str.length();\r
+               while (start < length) {\r
+                       int lineEnd = start + computeVisibleGlpyhs(str, start, indexOf(str, '\n', start), wrapWidth);\r
+                       if (lineEnd < length) {\r
+                               while (lineEnd > start) {\r
+                                       char ch = str.charAt(lineEnd);\r
+                                       if (ch == ' ' || ch == '\n') break;\r
+                                       lineEnd--;\r
+                               }\r
+                       }\r
+                       if (lineEnd == start) lineEnd++;\r
+                       float xOffset = 0;\r
+                       if (alignment != HAlignment.LEFT) {\r
+                               int lineWidth = getBounds(str, start, lineEnd).width;\r
+                               xOffset = wrapWidth - lineWidth;\r
+                               if (alignment == HAlignment.CENTER) xOffset /= 2;\r
+                       }\r
+                       draw(spriteBatch, str, x + xOffset, y, color, start, lineEnd);\r
+                       start = lineEnd + 1;\r
+                       y += down;\r
+                       numLines++;\r
+               }\r
+               return capHeight + (numLines - 1) * lineHeight;\r
+       }\r
+\r
+       /**\r
+        * Computes the width of the string.\r
+        * @param str The string\r
+        * @return the width\r
+        */\r
+       public TextBounds getBounds (CharSequence str) {\r
+               return getBounds(str, 0, str.length());\r
+       }\r
+\r
+       /**\r
+        * Computes the width of the string.\r
+        * @param str the string\r
+        * @param start The first character index\r
+        * @param end The last character index (exclusive)\r
+        * @return The string width\r
+        */\r
+       public TextBounds getBounds (CharSequence str, int start, int end) {\r
+               int width = 0;\r
+               Glyph lastGlyph = null;\r
+               while (start < end) {\r
+                       lastGlyph = getGlyph(str.charAt(start++));\r
+                       if (lastGlyph != null) {\r
+                               width = lastGlyph.xadvance;\r
+                               break;\r
+                       }\r
+               }\r
+               while (start < end) {\r
+                       char ch = str.charAt(start++);\r
+                       Glyph g = getGlyph(ch);\r
+                       if (g != null) {\r
+                               width += lastGlyph.getKerning(ch);\r
+                               lastGlyph = g;\r
+                               width += g.xadvance;\r
+                       }\r
+               }\r
+               textBounds.width = width;\r
+               textBounds.height = capHeight;\r
+               return textBounds;\r
+       }\r
+\r
+       /**\r
+        * Computes the maximum width of the string, respecting newlines.\r
+        * @param str The string\r
+        * @return The maximum width\r
+        */\r
+       public TextBounds getMultiLineBounds (CharSequence str) {\r
+               int start = 0;\r
+               int maxWidth = 0;\r
+               int numLines = 0;\r
+               int length = str.length();\r
+               while (start < length) {\r
+                       int lineEnd = indexOf(str, '\n', start);\r
+                       int lineWidth = getBounds(str, start, lineEnd).width;\r
+                       maxWidth = Math.max(maxWidth, lineWidth);\r
+                       start = lineEnd + 1;\r
+                       numLines++;\r
+               }\r
+               textBounds.width = maxWidth;\r
+               textBounds.height = capHeight + (numLines - 1) * lineHeight;\r
+               return textBounds;\r
+       }\r
+\r
+       public TextBounds getWrappedBounds (CharSequence str, float wrapWidth) {\r
+               int start = 0;\r
+               int maxWidth = 0;\r
+               int numLines = 0;\r
+               int length = str.length();\r
+               while (start < length) {\r
+                       int lineEnd = start + computeVisibleGlpyhs(str, start, indexOf(str, '\n', start), wrapWidth);\r
+                       if (lineEnd < length) {\r
+                               while (lineEnd > start) {\r
+                                       char ch = str.charAt(lineEnd);\r
+                                       if (ch == ' ' || ch == '\n') break;\r
+                                       lineEnd--;\r
+                               }\r
+                       }\r
+                       if (lineEnd == start) lineEnd++;\r
+                       int lineWidth = getBounds(str, start, lineEnd).width;\r
+                       maxWidth = Math.max(maxWidth, lineWidth);\r
+                       start = lineEnd + 1;\r
+                       numLines++;\r
+               }\r
+               textBounds.width = maxWidth;\r
+               textBounds.height = capHeight + (numLines - 1) * lineHeight;\r
+               return textBounds;\r
+       }\r
+\r
+       /**\r
+        * Returns the number of characters that can be rendered given the available width.\r
+        * @param str The string\r
+        * @param start The start index of the first character\r
+        * @param end The index of the last character (exclusive)\r
+        * @param availableWidth the available width\r
+        * @return The number of characters that fit into availableWdith\r
+        */\r
+       public int computeVisibleGlpyhs (CharSequence str, int start, int end, float availableWidth) {\r
+               int index = start;\r
+               int width = 0;\r
+               Glyph lastGlyph = null;\r
+               for (; index < end; index++) {\r
+                       char ch = str.charAt(index);\r
+                       Glyph g = getGlyph(ch);\r
+                       if (g != null) {\r
+                               if (lastGlyph != null) width += lastGlyph.getKerning(ch);\r
+                               lastGlyph = g;\r
+                               if (width + g.width + g.xoffset > availableWidth) break;\r
+                               width += g.xadvance;\r
+                       }\r
+               }\r
+               return index - start;\r
+       }\r
+\r
+       /**\r
+        * @return The glyph sprite\r
+        */\r
+       public Sprite getSprite () {\r
+               return sprite;\r
+       }\r
+\r
+       /**\r
+        * @return The baseline offset, which is the distance from the drawing position to the line that most glyphs sit on\r
+        */\r
+       public int getBaseLine () {\r
+               return baseLine;\r
+       }\r
+\r
+       /**\r
+        * @return The line height, which is the distance from one line of text to the next\r
+        */\r
+       public int getLineHeight () {\r
+               return lineHeight;\r
+       }\r
+\r
+       /**\r
+        * @return The width of the space character\r
+        */\r
+       public int getSpaceWidth () {\r
+               return spaceWidth;\r
+       }\r
+\r
+       /**\r
+        * @return The x-height, which is the typical height of lowercase characters\r
+        */\r
+       public int getXHeight () {\r
+               return xHeight;\r
+       }\r
+\r
+       /**\r
+        * @return The cap height, which is the typical height of uppercase characters\r
+        */\r
+       public int getCapHeight () {\r
+               return capHeight;\r
+       }\r
+\r
+       /**\r
+        * Disposes the texture used by this BitmapFont's sprite.\r
+        */\r
+       public void dispose () {\r
+               sprite.getTexture().dispose();\r
+       }\r
+\r
+       static class Glyph {\r
+               int width, height;\r
+               float u, v, u2, v2;\r
+               int xoffset, yoffset;\r
+               int xadvance;\r
+               byte[][] kerning;\r
+\r
+               int getKerning (char ch) {\r
+                       if (kerning != null) {\r
+                               byte[] page = kerning[ch >>> LOG2_PAGE_SIZE];\r
+                               if (page != null) return page[ch & (PAGE_SIZE - 1)];\r
+                       }\r
+                       return 0;\r
+               }\r
+\r
+               void setKerning (int ch, int value) {\r
+                       if (kerning == null) kerning = new byte[PAGES][];\r
+                       byte[] page = kerning[ch >>> LOG2_PAGE_SIZE];\r
+                       if (page == null) kerning[ch >>> LOG2_PAGE_SIZE] = page = new byte[PAGE_SIZE];\r
+                       page[ch & (PAGE_SIZE - 1)] = (byte)value;\r
+               }\r
+       }\r
+\r
+       static int indexOf (CharSequence text, char ch, int start) {\r
+               final int n = text.length();\r
+               for (; start < n; start++)\r
+                       if (text.charAt(start) == ch) return start;\r
+               return n;\r
+       }\r
+\r
+       static public class TextBounds {\r
+               public int width;\r
+               public int height;\r
+       }\r
+\r
+       static public enum HAlignment {\r
+               LEFT, CENTER, RIGHT\r
+       }\r
 }\r
index 876ca56..4c2f313 100644 (file)
@@ -26,12 +26,9 @@ import com.badlogic.gdx.graphics.BitmapFont.Glyph;
 import com.badlogic.gdx.graphics.BitmapFont.HAlignment;\r
 \r
 /**\r
- * A BitmapFontCache caches glyph geometry for a BitmapFont, providing a fast\r
- * way to render static text. <br>\r
+ * A BitmapFontCache caches glyph geometry for a BitmapFont, providing a fast way to render static text. <br>\r
  * <br>\r
- * The code is heavily based on Matthias Mann's TWL BitmapFont class. Thanks for\r
- * sharing, Matthias! :)\r
- * \r
+ * The code is heavily based on Matthias Mann's TWL BitmapFont class. Thanks for sharing, Matthias! :)\r
  * @author Nathan Sweet <misc@n4te.com>\r
  * @author Matthias Mann\r
  */\r
@@ -43,34 +40,26 @@ public class BitmapFontCache {
        private float x, y;\r
        private float color;\r
 \r
-       public BitmapFontCache(BitmapFont font) {\r
+       public BitmapFontCache (BitmapFont font) {\r
                this.font = font;\r
        }\r
 \r
        /**\r
-        * Sets the position of the text, relative to the position when the cached\r
-        * text was created.\r
-        * \r
-        * @param x\r
-        *            The x coordinate\r
-        * @param y\r
-        *            The y coodinate\r
+        * Sets the position of the text, relative to the position when the cached text was created.\r
+        * @param x The x coordinate\r
+        * @param y The y coodinate\r
         */\r
-       public void setPosition(float x, float y) {\r
+       public void setPosition (float x, float y) {\r
                translate(x - this.x, y - this.y);\r
        }\r
 \r
        /**\r
         * Sets the position of the text, relative to its current position.\r
-        * \r
-        * @param xAmount\r
-        *            The amount in x to move the text\r
-        * @param yAmount\r
-        *            The amount in y to move the text\r
+        * @param xAmount The amount in x to move the text\r
+        * @param yAmount The amount in y to move the text\r
         */\r
-       public void translate(float xAmount, float yAmount) {\r
-               if (xAmount == 0 && yAmount == 0)\r
-                       return;\r
+       public void translate (float xAmount, float yAmount) {\r
+               if (xAmount == 0 && yAmount == 0) return;\r
                x += xAmount;\r
                y += yAmount;\r
                float[] vertices = this.vertices;\r
@@ -82,14 +71,11 @@ public class BitmapFontCache {
 \r
        /**\r
         * Sets the tint color of the text.\r
-        * \r
-        * @param tint\r
-        *            The {@link Color}\r
+        * @param tint The {@link Color}\r
         */\r
-       public void setColor(Color tint) {\r
+       public void setColor (Color tint) {\r
                final float color = tint.toFloatBits();\r
-               if (color == this.color)\r
-                       return;\r
+               if (color == this.color) return;\r
                this.color = color;\r
                float[] vertices = this.vertices;\r
                for (int i = 2, n = idx; i < n; i += 5)\r
@@ -99,12 +85,10 @@ public class BitmapFontCache {
        /**\r
         * Sets the tint color of the text.\r
         */\r
-       public void setColor(float r, float g, float b, float a) {\r
-               int intBits = ((int) (255 * a) << 24) | ((int) (255 * b) << 16)\r
-                               | ((int) (255 * g) << 8) | ((int) (255 * r));\r
+       public void setColor (float r, float g, float b, float a) {\r
+               int intBits = ((int)(255 * a) << 24) | ((int)(255 * b) << 16) | ((int)(255 * g) << 8) | ((int)(255 * r));\r
                float color = Float.intBitsToFloat(intBits);\r
-               if (color == this.color)\r
-                       return;\r
+               if (color == this.color) return;\r
                this.color = color;\r
                float[] vertices = this.vertices;\r
                for (int i = 2, n = idx; i < n; i += 5)\r
@@ -112,28 +96,25 @@ public class BitmapFontCache {
        }\r
 \r
        /**\r
-        * Draws the contents of the cache via a {@link SpriteBatch}. Must be called\r
-        * between a {@link SpriteBatch#begin()}/ {@link SpriteBatch#end()} pair.\r
-        * \r
-        * @param spriteBatch\r
-        *            The SpriteBatch\r
+        * Draws the contents of the cache via a {@link SpriteBatch}. Must be called between a {@link SpriteBatch#begin()}/\r
+        * {@link SpriteBatch#end()} pair.\r
+        * @param spriteBatch The SpriteBatch\r
         */\r
-       public void draw(SpriteBatch spriteBatch) {\r
+       public void draw (SpriteBatch spriteBatch) {\r
                spriteBatch.draw(font.getSprite().getTexture(), vertices, 0, idx);\r
        }\r
 \r
-       void reset(int glyphCount) {\r
+       void reset (int glyphCount) {\r
                x = 0;\r
                y = 0;\r
                idx = 0;\r
 \r
                int vertexCount = glyphCount * 20;\r
-               if (vertices == null || vertices.length < vertexCount)\r
-                       vertices = new float[vertexCount];\r
+               if (vertices == null || vertices.length < vertexCount) vertices = new float[vertexCount];\r
        }\r
 \r
-       private int addToCache(CharSequence str, int x, int y, float color,\r
-                       int start, int end) {\r
+       private int addToCache (CharSequence str, float x, float y, float color, int start, int end) {\r
+               float startX = x;\r
                BitmapFont font = this.font;\r
                Glyph lastGlyph = null;\r
                while (start < end) {\r
@@ -154,10 +135,10 @@ public class BitmapFontCache {
                                x += g.xadvance;\r
                        }\r
                }\r
-               return x;\r
+               return (int)(x - startX);\r
        }\r
 \r
-       void addGlyph(Glyph glyph, float x, float y, float color) {\r
+       void addGlyph (Glyph glyph, float x, float y, float color) {\r
                x += glyph.xoffset;\r
                y += glyph.yoffset;\r
                final float x2 = x + glyph.width;\r
@@ -194,94 +175,60 @@ public class BitmapFontCache {
        }\r
 \r
        /**\r
-        * Caches the given string at the given position with the given color in the\r
-        * provided {@link BitmapFontCache}.\r
-        * \r
-        * @param str\r
-        *            The string\r
-        * @param x\r
-        *            The x position of the left most character\r
-        * @param y\r
-        *            The y position of the left most character's top left corner\r
-        * @param tint\r
-        *            The color\r
+        * Caches the given string at the given position with the given color in the provided {@link BitmapFontCache}.\r
+        * @param str The string\r
+        * @param x The x position of the left most character\r
+        * @param y The y position of the left most character's top left corner\r
+        * @param tint The color\r
         */\r
-       public void setText(CharSequence str, int x, int y, Color tint) {\r
+       public void setText (CharSequence str, float x, float y, Color tint) {\r
                setText(str, x, y, tint, 0, str.length());\r
        }\r
 \r
        /**\r
-        * Caches the given string at the given position with the given color in the\r
-        * provided {@link BitmapFontCache}.\r
-        * \r
-        * @param str\r
-        *            The string\r
-        * @param x\r
-        *            The x position of the left most character\r
-        * @param y\r
-        *            The y position of the left most character's top left corner\r
-        * @param tint\r
-        *            The color\r
-        * @param start\r
-        *            The first character of the string to draw\r
-        * @param end\r
-        *            The last character of the string to draw\r
+        * Caches the given string at the given position with the given color in the provided {@link BitmapFontCache}.\r
+        * @param str The string\r
+        * @param x The x position of the left most character\r
+        * @param y The y position of the left most character's top left corner\r
+        * @param tint The color\r
+        * @param start The first character of the string to draw\r
+        * @param end The last character of the string to draw\r
         */\r
-       public void setText(CharSequence str, int x, int y, Color tint, int start,\r
-                       int end) {\r
+       public void setText (CharSequence str, float x, float y, Color tint, int start, int end) {\r
                final float color = tint.toFloatBits();\r
                reset(end - start);\r
                y += font.yOffset;\r
                width = addToCache(str, x, y, color, start, end);\r
-               height = font.lineHeight;\r
+               height = font.capHeight;\r
        }\r
 \r
        /**\r
-        * Caches the given string at the given position with the given color in the\r
-        * provided {@link BitmapFontCache}. The position coincides with the top\r
-        * left corner of the first line's glyph. The method interprets new lines.\r
-        * \r
-        * @param str\r
-        *            The string\r
-        * @param x\r
-        *            The x position of the left most character of the first line\r
-        * @param y\r
-        *            The y position of the left most character's top left corner of\r
-        *            the first line\r
-        * @param tint\r
-        *            The color\r
+        * Caches the given string at the given position with the given color in the provided {@link BitmapFontCache}. The position\r
+        * coincides with the top left corner of the first line's glyph. The method interprets new lines.\r
+        * @param str The string\r
+        * @param x The x position of the left most character of the first line\r
+        * @param y The y position of the left most character's top left corner of the first line\r
+        * @param tint The color\r
         */\r
-       public void setMultiLineText(CharSequence str, int x, int y, Color tint) {\r
+       public void setMultiLineText (CharSequence str, float x, float y, Color tint) {\r
                setMultiLineText(str, x, y, tint, 0, HAlignment.LEFT);\r
        }\r
 \r
        /**\r
-        * Caches the given string at the given position with the given color in the\r
-        * provided {@link BitmapFontCache}. The position coincides with the top\r
-        * left corner of the first line's glyph. The method interprets new lines. <br>\r
+        * Caches the given string at the given position with the given color in the provided {@link BitmapFontCache}. The position\r
+        * coincides with the top left corner of the first line's glyph. The method interprets new lines. <br>\r
         * <br>\r
-        * You can specify the horizontal alignment of the text with the\r
-        * <code>alignmentWidth</code> and <code>alignment</code> parameters. The\r
-        * first parameter specifies the width of the rectangle the text should be\r
-        * aligned in (x to x + alignmentWidth). The second parameter specifies the\r
-        * alignment itself.\r
-        * \r
-        * @param str\r
-        *            The string\r
-        * @param x\r
-        *            The x position of the left most character of the first line\r
-        * @param y\r
-        *            The y position of the left most character's top left corner of\r
-        *            the first line\r
-        * @param tint\r
-        *            The color\r
-        * @param alignmentWidth\r
-        *            The alignment width\r
-        * @param alignment\r
-        *            The horizontal alignment\r
+        * You can specify the horizontal alignment of the text with the <code>alignmentWidth</code> and <code>alignment</code>\r
+        * parameters. The first parameter specifies the width of the rectangle the text should be aligned in (x to x +\r
+        * alignmentWidth). The second parameter specifies the alignment itself.\r
+        * @param str The string\r
+        * @param x The x position of the left most character of the first line\r
+        * @param y The y position of the left most character's top left corner of the first line\r
+        * @param tint The color\r
+        * @param alignmentWidth The alignment width\r
+        * @param alignment The horizontal alignment\r
         */\r
-       public void setMultiLineText(CharSequence str, int x, int y, Color tint,\r
-                       int alignmentWidth, HAlignment alignment) {\r
+       public void setMultiLineText (CharSequence str, float x, float y, Color tint, float alignmentWidth, HAlignment alignment) {\r
                BitmapFont font = this.font;\r
 \r
                int length = str.length();\r
@@ -291,74 +238,56 @@ public class BitmapFontCache {
                y += font.yOffset;\r
                int down = font.down;\r
 \r
+               int maxWidth = 0;\r
+               float startY = y;\r
                int start = 0;\r
                int numLines = 0;\r
                while (start < length) {\r
                        int lineEnd = BitmapFont.indexOf(str, '\n', start);\r
-                       int xOffset = 0;\r
+                       float xOffset = 0;\r
                        if (alignment != HAlignment.LEFT) {\r
-                               int lineWidth = font.computeTextWidth(str, start, lineEnd);\r
+                               int lineWidth = font.getBounds(str, start, lineEnd).width;\r
                                xOffset = alignmentWidth - lineWidth;\r
-                               if (alignment == HAlignment.CENTER)\r
-                                       xOffset /= 2;\r
+                               if (alignment == HAlignment.CENTER) xOffset /= 2;\r
                        }\r
-                       addToCache(str, x + xOffset, y, color, start, lineEnd);\r
+                       int lineWidth = addToCache(str, x + xOffset, y, color, start, lineEnd);\r
+                       maxWidth = Math.max(maxWidth, lineWidth);\r
                        start = lineEnd + 1;\r
                        y += down;\r
                        numLines++;\r
                }\r
-               width = alignmentWidth;\r
-               height = start - y;\r
+               width = maxWidth;\r
+               height = font.capHeight + (numLines - 1) * font.lineHeight;\r
        }\r
 \r
        /**\r
-        * Caches the given string at the given position with the given color in the\r
-        * provided {@link BitmapFontCache}. The position coincides with the top\r
-        * left corner of the first line's glyph. This method interprets new lines\r
-        * and causes the text to wrap at spaces based on the given\r
-        * <code>wrapWidth</code>. The wrapped text is left aligned.\r
-        * \r
-        * @param str\r
-        *            The string\r
-        * @param x\r
-        *            The x position of the left most character of the first line\r
-        * @param y\r
-        *            The y position of the left most character's top left corner of\r
-        *            the first line\r
-        * @param tint\r
-        *            The color\r
-        * @param wrapWidth\r
-        *            The wrap width\r
+        * Caches the given string at the given position with the given color in the provided {@link BitmapFontCache}. The position\r
+        * coincides with the top left corner of the first line's glyph. This method interprets new lines and causes the text to wrap\r
+        * at spaces based on the given <code>wrapWidth</code>. The wrapped text is left aligned.\r
+        * @param str The string\r
+        * @param x The x position of the left most character of the first line\r
+        * @param y The y position of the left most character's top left corner of the first line\r
+        * @param tint The color\r
+        * @param wrapWidth The wrap width\r
         */\r
-       public void setWrappedText(CharSequence str, int x, int y, Color tint,\r
-                       int wrapWidth) {\r
+       public void setWrappedText (CharSequence str, float x, float y, Color tint, float wrapWidth) {\r
                setWrappedText(str, x, y, tint, wrapWidth, HAlignment.LEFT);\r
        }\r
 \r
        /**\r
-        * Caches the given string at the given position with the given color in the\r
-        * provided {@link BitmapFontCache}. The position coincides with the top\r
-        * left corner of the first line's glyph. This method interprets new lines\r
-        * and causes the text to wrap at spaces based on the given\r
-        * <code>wrapWidth</code>. <br>\r
+        * Caches the given string at the given position with the given color in the provided {@link BitmapFontCache}. The position\r
+        * coincides with the top left corner of the first line's glyph. This method interprets new lines and causes the text to wrap\r
+        * at spaces based on the given <code>wrapWidth</code>. <br>\r
         * <br>\r
-        * You can specify the horizontal alignment of the text within the\r
-        * <code>wrapWidth</code> by using the <code>alignment</code> parameter.\r
-        * \r
-        * @param str\r
-        *            The string\r
-        * @param x\r
-        *            The x position of the left most character of the first line\r
-        * @param y\r
-        *            The y position of the left most character's top left corner of\r
-        *            the first line\r
-        * @param tint\r
-        *            The color\r
-        * @param wrapWidth\r
-        *            The wrap width\r
+        * You can specify the horizontal alignment of the text within the <code>wrapWidth</code> by using the <code>alignment</code>\r
+        * parameter.\r
+        * @param str The string\r
+        * @param x The x position of the left most character of the first line\r
+        * @param y The y position of the left most character's top left corner of the first line\r
+        * @param tint The color\r
+        * @param wrapWidth The wrap width\r
         */\r
-       public void setWrappedText(CharSequence str, int x, int y, Color tint,\r
-                       int wrapWidth, HAlignment alignment) {\r
+       public void setWrappedText (CharSequence str, float x, float y, Color tint, float wrapWidth, HAlignment alignment) {\r
                BitmapFont font = this.font;\r
 \r
                int length = str.length();\r
@@ -368,65 +297,60 @@ public class BitmapFontCache {
                y += font.yOffset;\r
                int down = font.down;\r
 \r
+               int maxWidth = 0;\r
                int start = 0;\r
                int numLines = 0;\r
                while (start < length) {\r
-                       int lineEnd = start\r
-                                       + font.computeVisibleGlpyhs(str, start,\r
-                                                       BitmapFont.indexOf(str, '\n', start), wrapWidth);\r
+                       int lineEnd = start + font.computeVisibleGlpyhs(str, start, BitmapFont.indexOf(str, '\n', start), wrapWidth);\r
                        if (lineEnd < length) {\r
                                while (lineEnd > start) {\r
                                        char ch = str.charAt(lineEnd);\r
-                                       if (ch == ' ' || ch == '\n')\r
-                                               break;\r
+                                       if (ch == ' ' || ch == '\n') break;\r
                                        lineEnd--;\r
                                }\r
                        }\r
-                       if (lineEnd == start)\r
-                               lineEnd++;\r
-                       int xOffset = 0;\r
+                       if (lineEnd == start) lineEnd++;\r
+                       float xOffset = 0;\r
                        if (alignment != HAlignment.LEFT) {\r
-                               int lineWidth = font.computeTextWidth(str, start, lineEnd);\r
+                               int lineWidth = font.getBounds(str, start, lineEnd).width;\r
                                xOffset = wrapWidth - lineWidth;\r
-                               if (alignment == HAlignment.CENTER)\r
-                                       xOffset /= 2;\r
+                               if (alignment == HAlignment.CENTER) xOffset /= 2;\r
                        }\r
-                       addToCache(str, x + xOffset, y, color, start, lineEnd);\r
+                       int lineWidth = addToCache(str, x + xOffset, y, color, start, lineEnd);\r
+                       maxWidth = Math.max(maxWidth, lineWidth);\r
                        start = lineEnd + 1;\r
                        y += down;\r
                        numLines++;\r
                }\r
-               width = wrapWidth;\r
-               height = start - y;\r
+               width = maxWidth;\r
+               height = font.capHeight + (numLines - 1) * font.lineHeight;\r
        }\r
 \r
        /**\r
         * @return The width of the contained text\r
         */\r
-       public int getWidth() {\r
+       public int getWidth () {\r
                return width;\r
        }\r
 \r
        /**\r
         * @return The height of the contained text\r
         */\r
-       public int getHeight() {\r
+       public int getHeight () {\r
                return height;\r
        }\r
 \r
        /**\r
-        * @return The x coordinate of the contained text, relative to the position\r
-        *         when the cached text was created\r
+        * @return The x coordinate of the contained text, relative to the position when the cached text was created\r
         */\r
-       public float getX() {\r
+       public float getX () {\r
                return x;\r
        }\r
 \r
        /**\r
-        * @return The y coordinate of the contained text, relative to the position\r
-        *         when the cached text was created\r
+        * @return The y coordinate of the contained text, relative to the position when the cached text was created\r
         */\r
-       public float getY() {\r
+       public float getY () {\r
                return y;\r
        }\r
 }\r
index 19532bb..2b8d47b 100644 (file)
@@ -60,7 +60,7 @@ public class ParticleEffect {
                }\r
        }\r
 \r
-       public void setPosition (int x, int y) {\r
+       public void setPosition (float x, float y) {\r
                for (int i = 0, n = emitters.size(); i < n; i++)\r
                        emitters.get(i).setPosition(x, y);\r
        }\r
index 893341b..cec1f4f 100644 (file)
@@ -46,7 +46,7 @@ public class ParticleEmitter {
        private Sprite sprite;\r
        private Particle[] particles;\r
        private int minParticleCount, maxParticleCount = 4;\r
-       private int x, y;\r
+       private float x, y;\r
        private String name;\r
        private String imagePath;\r
        private int activeCount;\r
@@ -322,9 +322,9 @@ public class ParticleEmitter {
                particle.transparencyDiff = transparencyValue.newHighValue() - particle.transparency;\r
 \r
                // Spawn.\r
-               int x = this.x;\r
+               float x = this.x;\r
                if (xOffsetValue.active) x += (int)xOffsetValue.newLowValue();\r
-               int y = this.y;\r
+               float y = this.y;\r
                if (yOffsetValue.active) y += (int)yOffsetValue.newLowValue();\r
                switch (spawnShapeValue.shape) {\r
                case square: {\r
@@ -445,10 +445,10 @@ public class ParticleEmitter {
                return true;\r
        }\r
 \r
-       public void setPosition (int x, int y) {\r
+       public void setPosition (float x, float y) {\r
                if (attached) {\r
-                       int xAmount = x - this.x;\r
-                       int yAmount = y - this.y;\r
+                       float xAmount = x - this.x;\r
+                       float yAmount = y - this.y;\r
                        BitSet active = this.active;\r
                        int index = 0;\r
                        while (true) {\r
@@ -623,11 +623,11 @@ public class ParticleEmitter {
                return Math.min(1, durationTimer / (float)duration);\r
        }\r
 \r
-       public int getX () {\r
+       public float getX () {\r
                return x;\r
        }\r
 \r
-       public int getY () {\r
+       public float getY () {\r
                return y;\r
        }\r
 \r
diff --git a/tests/gdx-tests/src/com/badlogic/gdx/tests/BitmapFontAlignmentTest.java b/tests/gdx-tests/src/com/badlogic/gdx/tests/BitmapFontAlignmentTest.java
new file mode 100644 (file)
index 0000000..bffb43a
--- /dev/null
@@ -0,0 +1,185 @@
+\r
+package com.badlogic.gdx.tests;\r
+\r
+import com.badlogic.gdx.Files.FileType;\r
+import com.badlogic.gdx.Gdx;\r
+import com.badlogic.gdx.InputAdapter;\r
+import com.badlogic.gdx.graphics.BitmapFont;\r
+import com.badlogic.gdx.graphics.BitmapFont.TextBounds;\r
+import com.badlogic.gdx.graphics.BitmapFontCache;\r
+import com.badlogic.gdx.graphics.Color;\r
+import com.badlogic.gdx.graphics.GL10;\r
+import com.badlogic.gdx.graphics.Sprite;\r
+import com.badlogic.gdx.graphics.SpriteBatch;\r
+import com.badlogic.gdx.graphics.Texture.TextureFilter;\r
+import com.badlogic.gdx.graphics.Texture.TextureWrap;\r
+import com.badlogic.gdx.tests.utils.GdxTest;\r
+\r
+/**\r
+ * Shows how to align single line, wrapped, and multi line text within a rectangle.\r
+ */\r
+public class BitmapFontAlignmentTest extends GdxTest {\r
+       private SpriteBatch spriteBatch;\r
+       private BitmapFont font;\r
+       private BitmapFontCache cache;\r
+       private Sprite logoSprite;\r
+       int renderMode;\r
+\r
+       @Override public void create () {\r
+               spriteBatch = new SpriteBatch();\r
+\r
+               logoSprite = new Sprite(Gdx.graphics.newTexture(Gdx.files.getFileHandle("data/badlogic.jpg", FileType.Internal),\r
+                       TextureFilter.Linear, TextureFilter.Linear, TextureWrap.ClampToEdge, TextureWrap.ClampToEdge));\r
+               logoSprite.setColor(1, 1, 1, 0.6f);\r
+               logoSprite.setBounds(50, 100, 400, 100);\r
+\r
+               font = new BitmapFont(Gdx.files.getFileHandle("data/verdana39.fnt", FileType.Internal), Gdx.files.getFileHandle(\r
+                       "data/verdana39.png", FileType.Internal), false);\r
+               cache = new BitmapFontCache(font);\r
+\r
+               Gdx.input.setInputProcessor(new InputAdapter() {\r
+                       public boolean touchDown (int x, int y, int pointer) {\r
+                               renderMode = (renderMode + 1) % 6;\r
+                               return false;\r
+                       }\r
+               });\r
+       }\r
+\r
+       @Override public void render () {\r
+               GL10 gl = Gdx.graphics.getGL10();\r
+               gl.glClear(GL10.GL_COLOR_BUFFER_BIT);\r
+               spriteBatch.begin();\r
+               logoSprite.draw(spriteBatch);\r
+               switch (renderMode) {\r
+               case 0:\r
+                       renderSingleLine();\r
+                       break;\r
+               case 1:\r
+                       renderSingleLineCached();\r
+                       break;\r
+               case 2:\r
+                       renderWrapped();\r
+                       break;\r
+               case 3:\r
+                       renderWrappedCached();\r
+                       break;\r
+               case 4:\r
+                       renderMultiLine();\r
+                       break;\r
+               case 5:\r
+                       renderMultiLineCached();\r
+                       break;\r
+               }\r
+               spriteBatch.end();\r
+       }\r
+\r
+       private void renderSingleLine () {\r
+               String text = "Single Line";\r
+               float x = logoSprite.getX();\r
+               float y = logoSprite.getY();\r
+               float width = logoSprite.getWidth();\r
+               float height = logoSprite.getHeight();\r
+\r
+               TextBounds bounds = font.getBounds(text);\r
+               x += width / 2 - bounds.width / 2;\r
+               y += height / 2 + bounds.height / 2;\r
+\r
+               font.draw(spriteBatch, text, x, y, Color.WHITE);\r
+       }\r
+\r
+       private void renderSingleLineCached () {\r
+               String text = "Single Line Cached";\r
+               float x = logoSprite.getX();\r
+               float y = logoSprite.getY();\r
+               float width = logoSprite.getWidth();\r
+               float height = logoSprite.getHeight();\r
+\r
+               // Obviously you wouldn't set the cache text every frame in real code.\r
+               cache.setMultiLineText(text, 0, 0, Color.WHITE);\r
+\r
+               x += width / 2 - cache.getWidth() / 2;\r
+               y += height / 2 + cache.getHeight() / 2;\r
+               cache.setPosition(x, y);\r
+\r
+               cache.draw(spriteBatch);\r
+       }\r
+\r
+       private void renderWrapped () {\r
+               String text = "Wrapped Wrapped Wrapped Wrapped";\r
+               float x = logoSprite.getX();\r
+               float y = logoSprite.getY();\r
+               float width = logoSprite.getWidth();\r
+               float height = logoSprite.getHeight();\r
+\r
+               TextBounds bounds = font.getWrappedBounds(text, width);\r
+               x += width / 2 - bounds.width / 2;\r
+               y += height / 2 + bounds.height / 2;\r
+\r
+               font.drawWrapped(spriteBatch, text, x, y, Color.WHITE, width);\r
+\r
+               // Note that wrapped text can be aligned:\r
+               // font.drawWrapped(spriteBatch, text, x, y, Color.WHITE, width, HAlignment.CENTER);\r
+       }\r
+\r
+       private void renderWrappedCached () {\r
+               String text = "Wrapped Cached Wrapped Cached";\r
+               float x = logoSprite.getX();\r
+               float y = logoSprite.getY();\r
+               float width = logoSprite.getWidth();\r
+               float height = logoSprite.getHeight();\r
+\r
+               // Obviously you wouldn't set the cache text every frame in real code.\r
+               cache.setWrappedText(text, 0, 0, Color.WHITE, width);\r
+\r
+               // Note that wrapped text can be aligned:\r
+               // cache.setWrappedText(text, 0, 0, Color.WHITE, width, HAlignment.CENTER);\r
+\r
+               x += width / 2 - cache.getWidth() / 2;\r
+               y += height / 2 + cache.getHeight() / 2;\r
+               cache.setPosition(x, y);\r
+\r
+               cache.draw(spriteBatch);\r
+       }\r
+\r
+       private void renderMultiLine () {\r
+               String text = "Multi\nLine";\r
+               float x = logoSprite.getX();\r
+               float y = logoSprite.getY();\r
+               float width = logoSprite.getWidth();\r
+               float height = logoSprite.getHeight();\r
+\r
+               TextBounds bounds = font.getMultiLineBounds(text);\r
+               x += width / 2 - bounds.width / 2;\r
+               y += height / 2 + bounds.height / 2;\r
+\r
+               font.drawMultiLine(spriteBatch, text, x, y, Color.WHITE);\r
+\r
+               // Note that multi line text can be aligned:\r
+               // font.drawMultiLine(spriteBatch, text, x, y, Color.WHITE, width, HAlignment.CENTER);\r
+       }\r
+\r
+       private void renderMultiLineCached () {\r
+               String text = "Multi Line\nCached";\r
+               int lines = 2;\r
+               float x = logoSprite.getX();\r
+               float y = logoSprite.getY();\r
+               float width = logoSprite.getWidth();\r
+               float height = logoSprite.getHeight();\r
+\r
+               // Obviously you wouldn't set the cache text every frame in real code.\r
+               cache.setMultiLineText(text, 0, 0, Color.WHITE);\r
+\r
+               // Note that multi line text can be aligned:\r
+               // cache.setMultiLineText(text, 0, 0, Color.WHITE, width, HAlignment.CENTER);\r
+\r
+               x += width / 2 - cache.getWidth() / 2;\r
+               y += height / 2 + cache.getHeight() / 2;\r
+               cache.setPosition(x, y);\r
+\r
+               cache.draw(spriteBatch);\r
+       }\r
+\r
+       public boolean needsGL20 () {\r
+               return false;\r
+       }\r
+}\r
index 13cb4a2..2c9b363 100644 (file)
@@ -29,7 +29,6 @@ public class BitmapFontFlipTest extends GdxTest {
 \r
        @Override\r
        public void create () {\r
-               if (spriteBatch != null) return;\r
                spriteBatch = new SpriteBatch();\r
                spriteBatch.setProjectionMatrix(new Matrix4().setToOrtho(0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), 0, 0, 1));\r
 \r
@@ -56,19 +55,19 @@ public class BitmapFontFlipTest extends GdxTest {
                cache4 = new BitmapFontCache(font);\r
                cache5 = new BitmapFontCache(font);\r
 \r
-               cache1.setText("(cached)", 10, 320 - 36, Color.WHITE);\r
+               cache1.setText("(cached)", 10, 320 - 66, Color.WHITE);\r
 \r
                String text = "Sphinx of black quartz,\njudge my vow.";\r
-               cache2.setMultiLineText(text, 5, 320 - 270, Color.RED);\r
+               cache2.setMultiLineText(text, 5, 320 - 300, Color.RED);\r
 \r
                text = "How quickly\ndaft jumping zebras vex.";\r
-               cache3.setMultiLineText(text, 5, 320 - 170, Color.BLUE, 470, BitmapFont.HAlignment.CENTER);\r
+               cache3.setMultiLineText(text, 5, 320 - 200, Color.BLUE, 470, BitmapFont.HAlignment.CENTER);\r
 \r
                text = "Kerning: LYA moo";\r
-               cache4.setText(text, 210, 320 - 36, Color.WHITE, 0, text.length() - 3);\r
+               cache4.setText(text, 210, 320 - 66, Color.WHITE, 0, text.length() - 3);\r
 \r
                text = "Forsaking monastic tradition, twelve jovial friars gave\nup their vocation for a questionable existence on the flying trapeze.";\r
-               cache5.setWrappedText(text, 0, 320 - 270, red, 480, HAlignment.CENTER);\r
+               cache5.setWrappedText(text, 0, 320 - 300, red, 480, HAlignment.CENTER);\r
        }\r
 \r
        @Override\r
@@ -93,20 +92,20 @@ public class BitmapFontFlipTest extends GdxTest {
        private void renderNormal () {\r
                String text = "Forsaking monastic tradition, twelve jovial friars gave\nup their vocation for a questionable existence on the flying trapeze.";\r
                red.a = alpha;\r
-               font.drawWrappedText(spriteBatch, text, 0, 320 - 270, red, 480, HAlignment.CENTER);\r
+               font.drawWrapped(spriteBatch, text, 0, 320 - 300, red, 480, HAlignment.CENTER);\r
 \r
-               font.draw(spriteBatch, "(normal)", 10, 320 - 36, Color.WHITE);\r
+               font.draw(spriteBatch, "(normal)", 10, 320 - 66, Color.WHITE);\r
 \r
                if (alpha > 0.6f) return;\r
 \r
                text = "Sphinx of black quartz,\njudge my vow.";\r
-               font.drawMultiLineText(spriteBatch, text, 5, 320 - 270, Color.RED);\r
+               font.drawMultiLine(spriteBatch, text, 5, 320 - 300, Color.RED);\r
 \r
                text = "How quickly\ndaft jumping zebras vex.";\r
-               font.drawMultiLineText(spriteBatch, text, 5, 320 - 170, Color.BLUE, 470, BitmapFont.HAlignment.RIGHT);\r
+               font.drawMultiLine(spriteBatch, text, 5, 320 - 200, Color.BLUE, 470, BitmapFont.HAlignment.RIGHT);\r
 \r
                text = "Kerning: LYA moo";\r
-               font.draw(spriteBatch, text, 210, 320 - 36, Color.WHITE, 0, text.length() - 3);\r
+               font.draw(spriteBatch, text, 210, 320 - 66, Color.WHITE, 0, text.length() - 3);\r
        }\r
 \r
        private void renderCached () {\r
index c5b5ed6..59a08ea 100644 (file)
@@ -28,7 +28,13 @@ public class BitmapFontTest extends GdxTest {
        InputProcessor inputProcessor;\r
 \r
        @Override public void create () {\r
-               if (spriteBatch != null) return;\r
+               Gdx.input.setInputProcessor(new InputAdapter() {\r
+                       public boolean touchDown (int x, int y, int pointer) {\r
+                               renderMode = (renderMode + 1) % 2;\r
+                               return false;\r
+                       }\r
+               });\r
+\r
                spriteBatch = new SpriteBatch();\r
 \r
                logoSprite = new Sprite(Gdx.graphics.newTexture(Gdx.files.getFileHandle("data/badlogic.jpg", FileType.Internal),\r
@@ -53,19 +59,19 @@ public class BitmapFontTest extends GdxTest {
                cache4 = new BitmapFontCache(font);\r
                cache5 = new BitmapFontCache(font);\r
 \r
-               cache1.setText("(cached)", 10, 36, Color.WHITE);\r
+               cache1.setText("(cached)", 10, 66, Color.WHITE);\r
 \r
                String text = "Sphinx of black quartz,\njudge my vow.";\r
-               cache2.setMultiLineText(text, 5, 270, Color.RED);\r
+               cache2.setMultiLineText(text, 5, 300, Color.RED);\r
 \r
                text = "How quickly\ndaft jumping zebras vex.";\r
-               cache3.setMultiLineText(text, 5, 170, Color.BLUE, 470, BitmapFont.HAlignment.CENTER);\r
+               cache3.setMultiLineText(text, 5, 200, Color.BLUE, 470, BitmapFont.HAlignment.CENTER);\r
 \r
                text = "Kerning: LYA moo";\r
-               cache4.setText(text, 210, 36, Color.WHITE, 0, text.length() - 3);\r
+               cache4.setText(text, 210, 66, Color.WHITE, 0, text.length() - 3);\r
 \r
                text = "Forsaking monastic tradition, twelve jovial friars gave\nup their vocation for a questionable existence on the flying trapeze.";\r
-               cache5.setWrappedText(text, 0, 270, red, 480, HAlignment.CENTER);\r
+               cache5.setWrappedText(text, 0, 300, red, 480, HAlignment.CENTER);\r
        }\r
 \r
        @Override public void render () {\r
@@ -89,20 +95,20 @@ public class BitmapFontTest extends GdxTest {
        private void renderNormal () {\r
                String text = "Forsaking monastic tradition, twelve jovial friars gave\nup their vocation for a questionable existence on the flying trapeze.";\r
                red.a = alpha;\r
-               font.drawWrappedText(spriteBatch, text, 0, 270, red, 480, HAlignment.CENTER);\r
+               font.drawWrapped(spriteBatch, text, 0, 300, red, 480, HAlignment.CENTER);\r
 \r
-               font.draw(spriteBatch, "(normal)", 10, 36, Color.WHITE);\r
+               font.draw(spriteBatch, "(normal)", 10, 66, Color.WHITE);\r
 \r
                if (alpha > 0.6f) return;\r
 \r
                text = "Sphinx of black quartz,\njudge my vow.";\r
-               font.drawMultiLineText(spriteBatch, text, 5, 270, Color.RED);\r
+               font.drawMultiLine(spriteBatch, text, 5, 300, Color.RED);\r
 \r
                text = "How quickly\ndaft jumping zebras vex.";\r
-               font.drawMultiLineText(spriteBatch, text, 5, 170, Color.BLUE, 470, BitmapFont.HAlignment.RIGHT);\r
+               font.drawMultiLine(spriteBatch, text, 5, 200, Color.BLUE, 470, BitmapFont.HAlignment.RIGHT);\r
 \r
                text = "Kerning: LYA moo";\r
-               font.draw(spriteBatch, text, 210, 36, Color.WHITE, 0, text.length() - 3);\r
+               font.draw(spriteBatch, text, 210, 66, Color.WHITE, 0, text.length() - 3);\r
        }\r
 \r
        private void renderCached () {\r
index 19fe355..6429d70 100644 (file)
@@ -264,7 +264,7 @@ public class FilesTest extends GdxTest {
        @Override public void render () {\r
                Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);\r
                batch.begin();\r
-               font.drawMultiLineText(batch, message, 20, Gdx.graphics.getHeight() - 20, Color.WHITE);\r
+               font.drawMultiLine(batch, message, 20, Gdx.graphics.getHeight() - 20, Color.WHITE);\r
                batch.end();\r
        }\r
 \r
index 47c9459..0b3cbd5 100644 (file)
@@ -6,6 +6,7 @@ import java.util.List;
 import com.badlogic.gdx.tests.AlphaTest;\r
 import com.badlogic.gdx.tests.AudioDeviceTest;\r
 import com.badlogic.gdx.tests.AudioRecorderTest;\r
+import com.badlogic.gdx.tests.BitmapFontAlignmentTest;\r
 import com.badlogic.gdx.tests.BitmapFontFlipTest;\r
 import com.badlogic.gdx.tests.BitmapFontTest;\r
 import com.badlogic.gdx.tests.Box2DTest;\r
@@ -38,8 +39,8 @@ import com.badlogic.gdx.tests.SoundTest;
 import com.badlogic.gdx.tests.SpriteBatchRotationTest;\r
 import com.badlogic.gdx.tests.SpriteBatchShaderTest;\r
 import com.badlogic.gdx.tests.SpriteBatchTest;\r
-import com.badlogic.gdx.tests.SpriteCacheTest;\r
 import com.badlogic.gdx.tests.SpriteCacheOffsetTest;\r
+import com.badlogic.gdx.tests.SpriteCacheTest;\r
 import com.badlogic.gdx.tests.SpritePerformanceTest;\r
 import com.badlogic.gdx.tests.SpriteSheetTest;\r
 import com.badlogic.gdx.tests.StageTest;\r
@@ -68,6 +69,7 @@ public class GdxTests
                AlphaTest.class,\r
                AudioDeviceTest.class,\r
                AudioRecorderTest.class,\r
+               BitmapFontAlignmentTest.class,\r
                BitmapFontFlipTest.class,\r
                BitmapFontTest.class,\r
                Box2DTest.class,\r