void setBitmapChar(BitmapCharacter bitmapChar) { x0 = Integer.MIN_VALUE; y0 = Integer.MIN_VALUE; width = Integer.MIN_VALUE; height = Integer.MIN_VALUE; alignX = 0; alignY = 0; BitmapCharacterSet charSet = font.getCharSet(); this.bitmapChar = bitmapChar; if (bitmapChar != null) { u0 = (float) bitmapChar.getX() / charSet.getWidth(); v0 = (float) bitmapChar.getY() / charSet.getHeight(); u1 = u0 + (float) bitmapChar.getWidth() / charSet.getWidth(); v1 = v0 + (float) bitmapChar.getHeight() / charSet.getHeight(); } else { u0 = 0; v0 = 0; u1 = 0; v1 = 0; } }
void update(StringBlock block) { final float[] tabs = block.getTabPosition(); final float tabWidth = block.getTabWidth(); final Rectangle bound = getBound(block); sizeScale = block.getSize() / font.getCharSet().getRenderedSize(); lineY = computeLineY(block); if (isHead()) { x0 = getBound(block).x; y0 = lineY; width = 0; height = 0; xAdvance = 0; } else if (isTab()) { x0 = previous.getNextX(); width = tabWidth; y0 = lineY; height = 0; if (tabs != null && x0 < tabs[tabs.length - 1]) { for (int i = 0; i < tabs.length - 1; i++) { if (x0 > tabs[i] && x0 < tabs[i + 1]) { width = tabs[i + 1] - x0; } } } xAdvance = width; } else if (bitmapChar == null) { x0 = getPrevious().getX1(); y0 = lineY; width = 0; height = 0; xAdvance = 0; } else { float xOffset = bitmapChar.getXOffset() * sizeScale; float yOffset = bitmapChar.getYOffset() * sizeScale; xAdvance = bitmapChar.getXAdvance() * sizeScale; width = bitmapChar.getWidth() * sizeScale; height = bitmapChar.getHeight() * sizeScale; float incrScale = rightToLeft ? -1f : 1f; float kernAmount = 0f; if (previous.isHead() || previous.eol) { x0 = bound.x; // The first letter quad will be drawn right at the first // position... but it does not offset by the characters offset // amount. This means that we've potentially accumulated extra // pixels and the next letter won't get drawn far enough unless // we add this offset back into xAdvance.. by subtracting it. // This is the same thing that's done below because we've // technically baked the offset in just like below. It doesn't // look like it at first glance so I'm keeping it separate with // this comment. xAdvance -= xOffset * incrScale; } else { x0 = previous.getNextX() + xOffset * incrScale; // Since x0 will have offset baked into it then we // need to counteract that in xAdvance. This is better // than removing it in getNextX() because we also need // to take kerning into account below... which will also // get baked in. // Without this, getNextX() will return values too far to // the left, for example. xAdvance -= xOffset * incrScale; } y0 = lineY + LINE_DIR * yOffset; // Adjust for kerning BitmapCharacter lastChar = previous.getBitmapChar(); if (lastChar != null && block.isKerning()) { kernAmount = lastChar.getKerning(c) * sizeScale; x0 += kernAmount * incrScale; // Need to unbake the kerning from xAdvance since it // is baked into x0... see above. // xAdvance -= kernAmount * incrScale; // No, kerning is an inter-character spacing and _does_ affect // all subsequent cursor positions. } } if (isEndOfLine()) { xAdvance = bound.x - x0; } }
public float getLineWidth(CharSequence text) { // This method will probably always be a bit of a maintenance // nightmare since it basis its calculation on a different // routine than the Letters class. The ideal situation would // be to abstract out letter position and size into its own // class that both BitmapFont and Letters could use for // positioning. // If getLineWidth() here ever again returns a different value // than Letters does with the same text then it might be better // just to create a Letters object for the sole purpose of // getting a text size. It's less efficient but at least it // would be accurate. // And here I am mucking around in here again... // // A font character has a few values that are pertinent to the // line width: // xOffset // xAdvance // kerningAmount(nextChar) // // The way BitmapText ultimately works is that the first character // starts with xOffset included (ie: it is rendered at -xOffset). // Its xAdvance is wider to accomodate that initial offset. // The cursor position is advanced by xAdvance each time. // // So, a width should be calculated in a similar way. Start with // -xOffset + xAdvance for the first character and then each subsequent // character is just xAdvance more 'width'. // // The kerning amount from one character to the next affects the // cursor position of that next character and thus the ultimate width // and so must be factored in also. float lineWidth = 0f; float maxLineWidth = 0f; char lastChar = 0; boolean firstCharOfLine = true; // float sizeScale = (float) block.getSize() / charSet.getRenderedSize(); float sizeScale = 1f; for (int i = 0; i < text.length(); i++) { char theChar = text.charAt(i); if (theChar == '\n') { maxLineWidth = Math.max(maxLineWidth, lineWidth); lineWidth = 0f; firstCharOfLine = true; continue; } BitmapCharacter c = charSet.getCharacter((int) theChar); if (c != null) { if (theChar == '\\' && i < text.length() - 1 && text.charAt(i + 1) == '#') { if (i + 5 < text.length() && text.charAt(i + 5) == '#') { i += 5; continue; } else if (i + 8 < text.length() && text.charAt(i + 8) == '#') { i += 8; continue; } } if (!firstCharOfLine) { lineWidth += findKerningAmount(lastChar, theChar) * sizeScale; } else { // The first character needs to add in its xOffset but it // is the only one... and negative offsets = postive width // because we're trying to account for the part that hangs // over the left. So we subtract. lineWidth -= c.getXOffset() * sizeScale; firstCharOfLine = false; } float xAdvance = c.getXAdvance() * sizeScale; // If this is the last character, then we really should have // only add its width. The advance may include extra spacing // that we don't care about. if (i == text.length() - 1) { lineWidth += c.getWidth() * sizeScale; // Since theh width includes the xOffset then we need // to take it out again by adding it, ie: offset the width // we just added by the appropriate amount. lineWidth += c.getXOffset() * sizeScale; } else { lineWidth += xAdvance; } } } return Math.max(maxLineWidth, lineWidth); }