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
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
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
\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
/**\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
}\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
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
}\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
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
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