/** * Initialise the font to be used based on configuration * * @param baseFont The AWT font to render * @param size The point size of the font to generated * @param bold True if the font should be rendered in bold typeface * @param italic True if the font should be rendered in bold typeface */ private void initializeFont(Font baseFont, int size, boolean bold, boolean italic) { Map attributes = baseFont.getAttributes(); attributes.put(TextAttribute.SIZE, new Float(size)); attributes.put(TextAttribute.WEIGHT, bold ? TextAttribute.WEIGHT_BOLD : TextAttribute.WEIGHT_REGULAR); attributes.put(TextAttribute.POSTURE, italic ? TextAttribute.POSTURE_OBLIQUE : TextAttribute.POSTURE_REGULAR); try { attributes.put(TextAttribute.class.getDeclaredField("KERNING").get(null), TextAttribute.class.getDeclaredField( "KERNING_ON").get(null)); } catch (Exception ignored) { } font = baseFont.deriveFont(attributes); FontMetrics metrics = GlyphPage.getScratchGraphics().getFontMetrics(font); ascent = metrics.getAscent(); descent = metrics.getDescent(); leading = metrics.getLeading(); // Determine width of space glyph (getGlyphPixelBounds gives a width of zero). char[] chars = " ".toCharArray(); GlyphVector vector = font.layoutGlyphVector(GlyphPage.renderContext, chars, 0, chars.length, Font.LAYOUT_LEFT_TO_RIGHT); spaceWidth = vector.getGlyphLogicalBounds(0).getBounds().width; }
/** * Clears all loaded and queued glyphs. */ public void clearGlyphs () { for (int i = 0; i < PAGES; i++) glyphs[i] = null; for (Iterator iter = glyphPages.iterator(); iter.hasNext();) { GlyphPage page = (GlyphPage)iter.next(); try { page.getImage().destroy(); } catch (SlickException ignored) { } } glyphPages.clear(); if (baseDisplayListID != -1) { GL.glDeleteLists(baseDisplayListID, displayLists.size()); baseDisplayListID = -1; } queuedGlyphs.clear(); missingGlyph = null; }
/** * @param text the string to find the width of * @param logical whether to add the space the letters should occupy on the end * @return width of string. */ private int findWidth(String text,boolean logical) { char[] chars = text.toCharArray(); GlyphVector vector = font.layoutGlyphVector(GlyphPage.renderContext, chars, 0, chars.length, Font.LAYOUT_LEFT_TO_RIGHT); int width = 0; int extraX = 0; boolean startNewLine = false; for (int glyphIndex = 0, n = vector.getNumGlyphs(); glyphIndex < n; glyphIndex++) { int charIndex = vector.getGlyphCharIndex(glyphIndex); int codePoint = text.codePointAt(charIndex); Rectangle bounds = logical ? vector.getLogicalBounds().getBounds() : getGlyphBounds(vector, glyphIndex, codePoint); if (startNewLine && codePoint != '\n') extraX = -bounds.x; if (glyphIndex > 0) extraX += paddingLeft + paddingRight + paddingAdvanceX; width = Math.max(width, bounds.x + extraX + bounds.width); if (codePoint == '\n') startNewLine = true; } return width; }
/** * Initialise the font to be used based on configuration * * @param baseFont The AWT font to render * @param size The point size of the font to generated * @param bold True if the font should be rendered in bold typeface * @param italic True if the font should be rendered in bold typeface */ @SuppressWarnings({"unchecked","rawtypes"}) private void initializeFont(@Nonnull Font baseFont, int size, boolean bold, boolean italic) { Map attributes = baseFont.getAttributes(); attributes.put(TextAttribute.SIZE, (float) size); attributes.put(TextAttribute.WEIGHT, bold ? TextAttribute.WEIGHT_BOLD : TextAttribute.WEIGHT_REGULAR); attributes.put(TextAttribute.POSTURE, italic ? TextAttribute.POSTURE_OBLIQUE : TextAttribute.POSTURE_REGULAR); try { attributes.put(TextAttribute.class.getDeclaredField("KERNING").get(null), TextAttribute.class.getDeclaredField( "KERNING_ON").get(null)); } catch (Exception ignored) { } font = baseFont.deriveFont(attributes); FontMetrics metrics = GlyphPage.getScratchGraphics().getFontMetrics(font); ascent = metrics.getAscent(); descent = metrics.getDescent(); leading = metrics.getLeading(); // Determine width of space glyph (getGlyphPixelBounds gives a width of zero). char[] chars = " ".toCharArray(); GlyphVector vector = font.layoutGlyphVector(GlyphPage.renderContext, chars, 0, chars.length, Font.LAYOUT_LEFT_TO_RIGHT); spaceWidth = vector.getGlyphLogicalBounds(0).getBounds().width; }
/** * Clears all loaded and queued glyphs. */ void clearGlyphs() { for (int i = 0; i < PAGES; i++) glyphs[i] = null; for (GlyphPage page : glyphPages) { page.getImage().destroy(); } glyphPages.clear(); if (baseDisplayListID != -1) { GL.glDeleteLists(baseDisplayListID, displayLists.size()); baseDisplayListID = -1; } queuedGlyphs.clear(); missingGlyph = null; }
/** * Queues the glyphs in the specified text to be loaded. Note that the glyphs are not actually loaded until * {@link #loadGlyphs()} is called. * * @param text The text containing the glyphs to be added */ public void addGlyphs(String text) { if (text == null) throw new IllegalArgumentException("text cannot be null."); char[] chars = text.toCharArray(); GlyphVector vector = font.layoutGlyphVector(GlyphPage.renderContext, chars, 0, chars.length, Font.LAYOUT_LEFT_TO_RIGHT); for (int i = 0, n = vector.getNumGlyphs(); i < n; i++) { int codePoint = text.codePointAt(vector.getGlyphCharIndex(i)); if (backup != null && !font.canDisplay((char) codePoint) && backup.getFont().canDisplay((char) codePoint)) { addBackupGlyphs(new String(Character.toChars(codePoint))); continue; } Rectangle bounds = getGlyphBounds(vector, i, codePoint); getGlyph(vector.getGlyphCode(i), codePoint, bounds, vector, i); } }
/** * Queues the glyphs in the specified text to be loaded. Note that the glyphs are not actually loaded until * {@link #loadGlyphs()} is called. * * @param text The text containing the glyphs to be added */ public void addGlyphs(String text) { if (text == null) throw new IllegalArgumentException("text cannot be null."); char[] chars = text.toCharArray(); GlyphVector vector = font.layoutGlyphVector(GlyphPage.renderContext, chars, 0, chars.length, Font.LAYOUT_LEFT_TO_RIGHT); for (int i = 0, n = vector.getNumGlyphs(); i < n; i++) { int codePoint = text.codePointAt(vector.getGlyphCharIndex(i)); Rectangle bounds = getGlyphBounds(vector, i, codePoint); getGlyph(vector.getGlyphCode(i), codePoint, bounds, vector, i); } }
/** * @see org.newdawn.slick.Font#getHeight(java.lang.String) */ public int getHeight (String text) { if (text == null) throw new IllegalArgumentException("text cannot be null."); if (text.length() == 0) return 0; if (displayListCaching) { DisplayList displayList = (DisplayList)displayLists.get(text); if (displayList != null) return displayList.height; } char[] chars = text.toCharArray(); GlyphVector vector = font.layoutGlyphVector(GlyphPage.renderContext, chars, 0, chars.length, Font.LAYOUT_LEFT_TO_RIGHT); int lines = 0, height = 0; for (int i = 0, n = vector.getNumGlyphs(); i < n; i++) { int charIndex = vector.getGlyphCharIndex(i); int codePoint = text.codePointAt(charIndex); if (codePoint == ' ') continue; Rectangle bounds = getGlyphBounds(vector, i, codePoint); height = Math.max(height, ascent + bounds.y + bounds.height); if (codePoint == '\n') { lines++; height = 0; } } return lines * getLineHeight() + height; }
/** * Returns an image that can be used by effects as a temp image. * * @return The scratch image used for temporary operations */ static public BufferedImage getScratchImage() { Graphics2D g = (Graphics2D)scratchImage.getGraphics(); g.setComposite(AlphaComposite.Clear); g.fillRect(0, 0, GlyphPage.MAX_GLYPH_SIZE, GlyphPage.MAX_GLYPH_SIZE); g.setComposite(AlphaComposite.SrcOver); g.setColor(java.awt.Color.white); return scratchImage; }
private int[] getGlyphMetrics (Font font, int codePoint) { // xOffset and xAdvance will be incorrect for unicode characters such as combining marks or non-spacing characters // (eg Pnujabi's "\u0A1C\u0A47") that require the context of surrounding glyphs to determine spacing, but thisis the // best we can do with the BMFont format. char[] chars = Character.toChars(codePoint); GlyphVector vector = font.layoutGlyphVector(GlyphPage.renderContext, chars, 0, chars.length, Font.LAYOUT_LEFT_TO_RIGHT); GlyphMetrics metrics = vector.getGlyphMetrics(0); int xOffset = vector.getGlyphPixelBounds(0, null, 0, 0).x - unicodeFont.getPaddingLeft(); int xAdvance = (int)(metrics.getAdvanceX() + unicodeFont.getPaddingAdvanceX() + unicodeFont.getPaddingLeft() + unicodeFont .getPaddingRight()); return new int[] {xOffset, xAdvance}; }
/** * Queues the glyphs in the specified text to be loaded. Note that the glyphs are not actually loaded until * {@link #loadGlyphs()} is called. * * @param text The text containing the glyphs to be added */ void addGlyphs(@Nullable String text) { if (text == null) throw new IllegalArgumentException("text cannot be null."); char[] chars = text.toCharArray(); GlyphVector vector = font.layoutGlyphVector(GlyphPage.renderContext, chars, 0, chars.length, Font.LAYOUT_LEFT_TO_RIGHT); for (int i = 0, n = vector.getNumGlyphs(); i < n; i++) { int codePoint = text.codePointAt(vector.getGlyphCharIndex(i)); Rectangle bounds = getGlyphBounds(vector, i, codePoint); getGlyph(vector.getGlyphCode(i), codePoint, bounds, vector, i); } }
/** * @see org.newdawn.slick.Font#getHeight(CharSequence) */ public int getHeight (@Nullable CharSequence text) { if (text == null) throw new IllegalArgumentException("text cannot be null."); if (text.length() == 0) return 0; if (displayListCaching) { DisplayList displayList = displayLists.get(text); if (displayList != null) return displayList.height; } char[] chars = toCharArray(text, 0, text.length()); GlyphVector vector = font.layoutGlyphVector(GlyphPage.renderContext, chars, 0, chars.length, Font.LAYOUT_LEFT_TO_RIGHT); int lines = 0, height = 0; for (int i = 0, n = vector.getNumGlyphs(); i < n; i++) { int charIndex = vector.getGlyphCharIndex(i); int codePoint = Character.codePointAt(text, charIndex); if (codePoint == ' ') continue; Rectangle bounds = getGlyphBounds(vector, i, codePoint); height = Math.max(height, ascent + bounds.y + bounds.height); if (codePoint == '\n') { lines++; height = 0; } } return lines * getLineHeight() + height; }