From 67ec86e539a3db0d06e5cc3550db453589594384 Mon Sep 17 00:00:00 2001 From: Sven Gothel Date: Thu, 27 Feb 2014 23:56:13 +0100 Subject: Bug 801: Graph TextRenderer Cleanup Part-4: Text[Render->Region]Util API: Better separation of cached and uncached regions --- .../jogamp/graph/curve/opengl/TextRegionUtil.java | 262 ++++++++++++++++++++ .../jogamp/graph/curve/opengl/TextRenderUtil.java | 273 --------------------- src/jogl/classes/com/jogamp/graph/font/Font.java | 6 +- .../jogamp/graph/font/typecast/TypecastFont.java | 43 ++-- 4 files changed, 290 insertions(+), 294 deletions(-) create mode 100644 src/jogl/classes/com/jogamp/graph/curve/opengl/TextRegionUtil.java delete mode 100644 src/jogl/classes/com/jogamp/graph/curve/opengl/TextRenderUtil.java (limited to 'src/jogl') diff --git a/src/jogl/classes/com/jogamp/graph/curve/opengl/TextRegionUtil.java b/src/jogl/classes/com/jogamp/graph/curve/opengl/TextRegionUtil.java new file mode 100644 index 000000000..e7ed335ec --- /dev/null +++ b/src/jogl/classes/com/jogamp/graph/curve/opengl/TextRegionUtil.java @@ -0,0 +1,262 @@ +/** + * Copyright 2014 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package com.jogamp.graph.curve.opengl; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; + +import javax.media.opengl.GL2ES2; +import javax.media.opengl.GLException; + +import jogamp.graph.geom.plane.AffineTransform; + +import com.jogamp.graph.curve.OutlineShape; +import com.jogamp.graph.curve.Region; +import com.jogamp.graph.font.Font; +import com.jogamp.graph.font.Font.Glyph; +import com.jogamp.graph.geom.Vertex; +import com.jogamp.graph.geom.Vertex.Factory; + +/** + * Text {@link GLRegion} Utility Class + */ +public class TextRegionUtil { + + public final RegionRenderer renderer; + + public TextRegionUtil(final RegionRenderer renderer) { + this.renderer = renderer; + } + + /** + * Add the string in 3D space w.r.t. the font and pixelSize at the end of the {@link GLRegion}. + * @param region the {@link GLRegion} sink + * @param vertexFactory vertex impl factory {@link Factory} + * @param font the target {@link Font} + * @param str string text + * @param pixelSize + */ + public static void addStringToRegion(final GLRegion region, final Factory vertexFactory, + final Font font, final CharSequence str, final int pixelSize) { + final int charCount = str.length(); + + // region.setFlipped(true); + final Font.Metrics metrics = font.getMetrics(); + final float lineHeight = font.getLineHeight(pixelSize); + + final float scale = metrics.getScale(pixelSize); + final AffineTransform transform = new AffineTransform(vertexFactory); + final AffineTransform t = new AffineTransform(vertexFactory); + + float y = 0; + float advanceTotal = 0; + + for(int i=0; i< charCount; i++) { + final char character = str.charAt(i); + if( '\n' == character ) { + y -= lineHeight; + advanceTotal = 0; + } else if (character == ' ') { + advanceTotal += font.getAdvanceWidth(Glyph.ID_SPACE, pixelSize); + } else { + if(Region.DEBUG_INSTANCE) { + System.err.println("XXXXXXXXXXXXXXx char: "+character+", scale: "+scale+"; translate: "+advanceTotal+", "+y); + } + t.setTransform(transform); // reset transform + t.translate(advanceTotal, y); + t.scale(scale, scale); + + final Font.Glyph glyph = font.getGlyph(character); + final OutlineShape glyphShape = glyph.getShape(); + if( null == glyphShape ) { + continue; + } + region.addOutlineShape(glyphShape, t); + + advanceTotal += glyph.getAdvance(pixelSize, true); + } + } + } + + /** + * Render the string in 3D space w.r.t. the font and pixelSize + * using a cached {@link GLRegion} for reuse. + *

+ * Cached {@link GLRegion}s will be destroyed w/ {@link #clear(GL2ES2)} or to free memory. + *

+ * @param gl the current GL state + * @param font {@link Font} to be used + * @param str text to be rendered + * @param pixelSize font size + * @param texSize desired texture width for multipass-rendering. + * The actual used texture-width is written back when mp rendering is enabled, otherwise the store is untouched. + * @throws Exception if TextRenderer not initialized + */ + public void drawString3D(final GL2ES2 gl, + final Font font, final CharSequence str, final int pixelSize, + final int[/*1*/] texSize) { + if( !renderer.isInitialized() ) { + throw new GLException("TextRendererImpl01: not initialized!"); + } + final RenderState rs = renderer.getRenderState(); + GLRegion region = getCachedRegion(font, str, pixelSize); + if(null == region) { + region = GLRegion.create(renderer.getRenderModes()); + addStringToRegion(region, rs.getVertexFactory(), font, str, pixelSize); + addCachedRegion(gl, font, str, pixelSize, region); + } + region.draw(gl, renderer, texSize); + } + + /** + * Render the string in 3D space w.r.t. the font and pixelSize + * using a temporary {@link GLRegion}, which will be destroyed afterwards. + * @param gl the current GL state + * @param font {@link Font} to be used + * @param str text to be rendered + * @param fontSize font size + * @param texWidth desired texture width for multipass-rendering. + * The actual used texture-width is written back when mp rendering is enabled, otherwise the store is untouched. + * @throws Exception if TextRenderer not initialized + */ + public static void drawString3D(final RegionRenderer renderer, final GL2ES2 gl, + final Font font, final CharSequence str, final int fontSize, + final int[/*1*/] texSize) { + if(!renderer.isInitialized()){ + throw new GLException("TextRendererImpl01: not initialized!"); + } + final RenderState rs = renderer.getRenderState(); + final GLRegion region = GLRegion.create(renderer.getRenderModes()); + addStringToRegion(region, rs.getVertexFactory(), font, str, fontSize); + region.draw(gl, renderer, texSize); + region.destroy(gl, renderer); + } + + /** + * Clear all cached {@link GLRegions}. + */ + public void clear(GL2ES2 gl) { + // fluchCache(gl) already called + final Iterator iterator = stringCacheMap.values().iterator(); + while(iterator.hasNext()){ + final GLRegion region = iterator.next(); + region.destroy(gl, renderer); + } + stringCacheMap.clear(); + stringCacheArray.clear(); + } + + /** + *

Sets the cache limit for reusing GlyphString's and their Region. + * Default is {@link #DEFAULT_CACHE_LIMIT}, -1 unlimited, 0 turns cache off, >0 limited

+ * + *

The cache will be validate when the next string rendering happens.

+ * + * @param newLimit new cache size + * + * @see #DEFAULT_CACHE_LIMIT + */ + public final void setCacheLimit(int newLimit ) { stringCacheLimit = newLimit; } + + /** + * Sets the cache limit, see {@link #setCacheLimit(int)} and validates the cache. + * + * @see #setCacheLimit(int) + * + * @param gl current GL used to remove cached objects if required + * @param newLimit new cache size + */ + public final void setCacheLimit(GL2ES2 gl, int newLimit ) { stringCacheLimit = newLimit; validateCache(gl, 0); } + + /** + * @return the current cache limit + */ + public final int getCacheLimit() { return stringCacheLimit; } + + /** + * @return the current utilized cache size, <= {@link #getCacheLimit()} + */ + public final int getCacheSize() { return stringCacheArray.size(); } + + protected final void validateCache(GL2ES2 gl, int space) { + if ( getCacheLimit() > 0 ) { + while ( getCacheSize() + space > getCacheLimit() ) { + removeCachedRegion(gl, 0); + } + } + } + + protected final GLRegion getCachedRegion(Font font, CharSequence str, int fontSize) { + return stringCacheMap.get(getKey(font, str, fontSize)); + } + + protected final void addCachedRegion(GL2ES2 gl, Font font, CharSequence str, int fontSize, GLRegion glyphString) { + if ( 0 != getCacheLimit() ) { + final String key = getKey(font, str, fontSize); + final GLRegion oldRegion = stringCacheMap.put(key, glyphString); + if ( null == oldRegion ) { + // new entry .. + validateCache(gl, 1); + stringCacheArray.add(stringCacheArray.size(), key); + } /// else overwrite is nop .. + } + } + + protected final void removeCachedRegion(GL2ES2 gl, Font font, CharSequence str, int fontSize) { + final String key = getKey(font, str, fontSize); + GLRegion region = stringCacheMap.remove(key); + if(null != region) { + region.destroy(gl, renderer); + } + stringCacheArray.remove(key); + } + + protected final void removeCachedRegion(GL2ES2 gl, int idx) { + final String key = stringCacheArray.remove(idx); + if( null != key ) { + final GLRegion region = stringCacheMap.remove(key); + if(null != region) { + region.destroy(gl, renderer); + } + } + } + + protected final String getKey(Font font, CharSequence str, int fontSize) { + final StringBuilder sb = new StringBuilder(); + return font.getName(sb, Font.NAME_UNIQUNAME) + .append(".").append(str.hashCode()).append(".").append(fontSize).toString(); + } + + /** Default cache limit, see {@link #setCacheLimit(int)} */ + public static final int DEFAULT_CACHE_LIMIT = 256; + + private final HashMap stringCacheMap = new HashMap(DEFAULT_CACHE_LIMIT); + private final ArrayList stringCacheArray = new ArrayList(DEFAULT_CACHE_LIMIT); + private int stringCacheLimit = DEFAULT_CACHE_LIMIT; +} \ No newline at end of file diff --git a/src/jogl/classes/com/jogamp/graph/curve/opengl/TextRenderUtil.java b/src/jogl/classes/com/jogamp/graph/curve/opengl/TextRenderUtil.java deleted file mode 100644 index 944050a14..000000000 --- a/src/jogl/classes/com/jogamp/graph/curve/opengl/TextRenderUtil.java +++ /dev/null @@ -1,273 +0,0 @@ -/** - * Copyright 2014 JogAmp Community. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are - * permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list - * of conditions and the following disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The views and conclusions contained in the software and documentation are those of the - * authors and should not be interpreted as representing official policies, either expressed - * or implied, of JogAmp Community. - */ -package com.jogamp.graph.curve.opengl; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; - -import javax.media.opengl.GL2ES2; -import javax.media.opengl.GLException; - -import jogamp.graph.geom.plane.AffineTransform; - -import com.jogamp.graph.curve.OutlineShape; -import com.jogamp.graph.curve.Region; -import com.jogamp.graph.font.Font; -import com.jogamp.graph.font.Font.Glyph; -import com.jogamp.graph.geom.Triangle; -import com.jogamp.graph.geom.Vertex; -import com.jogamp.graph.geom.Vertex.Factory; - -/** - * - * FIXME: Add VBO Vertex Factory for drawString3D ! - * - */ -public class TextRenderUtil { - - public final RegionRenderer renderer; - - public TextRenderUtil(final RegionRenderer renderer) { - this.renderer = renderer; - } - - /** - * Generate a Region to represent this Object. - *

- * Each glyph is cached and reused. - *

- * - * @param renderModes bit-field of modes, e.g. {@link Region#VARIABLE_CURVE_WEIGHT_BIT}, {@link Region#VBAA_RENDERING_BIT} - * @param vertexFactory vertex impl factory {@link Factory} - * @param font the target {@link Font} - * @param str string text - * @param pixelSize - */ - public static GLRegion createRegion(final int renderModes, final Factory vertexFactory, - final Font font, final CharSequence str, final int pixelSize) { - final int charCount = str.length(); - - final GLRegion region = GLRegion.create(renderModes); - // region.setFlipped(true); - final Font.Metrics metrics = font.getMetrics(); - - final float lineGap = metrics.getLineGap(pixelSize) ; - final float ascent = metrics.getAscent(pixelSize) ; - final float descent = metrics.getDescent(pixelSize) ; - final float advanceY = lineGap - descent + ascent; - final float scale = metrics.getScale(pixelSize); - final AffineTransform transform = new AffineTransform(vertexFactory); - final AffineTransform t = new AffineTransform(vertexFactory); - - float y = 0; - float advanceTotal = 0; - - for(int i=0; i< charCount; i++) { - final char character = str.charAt(i); - if( '\n' == character ) { - y += advanceY; - advanceTotal = 0; - } else if (character == ' ') { - advanceTotal += font.getAdvanceWidth(Glyph.ID_SPACE, pixelSize); - } else { - if(Region.DEBUG_INSTANCE) { - System.err.println("XXXXXXXXXXXXXXx char: "+character+", scale: "+scale+"; translate: "+advanceTotal+", "+y); - } - t.setTransform(transform); // reset transform - t.translate(advanceTotal, y); - t.scale(scale, scale); - - final Font.Glyph glyph = font.getGlyph(character); - final OutlineShape glyphShape = glyph.getShape(); - if( null == glyphShape ) { - continue; - } - region.addOutlineShape(glyphShape, t); - - advanceTotal += glyph.getAdvance(pixelSize, true); - } - } - return region; - } - - /** - * Render the String in 3D space wrt to the font provided at the position provided - * the outlines will be generated, if not yet generated - * @param gl the current GL state - * @param font {@link Font} to be used - * @param str text to be rendered - * @param pixelSize font size - * @param texWidth desired texture width for multipass-rendering. - * The actual used texture-width is written back when mp rendering is enabled, otherwise the store is untouched. - * @throws Exception if TextRenderer not initialized - */ - public void drawString3D(final GL2ES2 gl, - final Font font, final CharSequence str, final int pixelSize, final int[/*1*/] texSize) { - if(!renderer.isInitialized()){ - throw new GLException("TextRendererImpl01: not initialized!"); - } - final RenderState rs = renderer.getRenderState(); - GLRegion region = getCachedRegion(font, str, pixelSize); - if(null == region) { - region = createRegion(renderer.getRenderModes(), rs.getVertexFactory(), font, str, pixelSize); - addCachedRegion(gl, font, str, pixelSize, region); - } - region.draw(gl, renderer, texSize); - } - - /** - * Render the String in 3D space wrt to the font provided at the position provided - * the outlines will be generated, if not yet generated - * @param gl the current GL state - * @param font {@link Font} to be used - * @param str text to be rendered - * @param fontSize font size - * @param texWidth desired texture width for multipass-rendering. - * The actual used texture-width is written back when mp rendering is enabled, otherwise the store is untouched. - * @throws Exception if TextRenderer not initialized - */ - public static void drawString3D(final RegionRenderer renderer, final GL2ES2 gl, - final Font font, final CharSequence str, final int fontSize, final int[/*1*/] texSize) { - if(!renderer.isInitialized()){ - throw new GLException("TextRendererImpl01: not initialized!"); - } - final RenderState rs = renderer.getRenderState(); - GLRegion region = createRegion(renderer.getRenderModes(), rs.getVertexFactory(), font, str, fontSize); - region.draw(gl, renderer, texSize); - } - - /** FIXME - public void flushCache(GL2ES2 gl) { - Iterator iterator = stringCacheMap.values().iterator(); - while(iterator.hasNext()){ - GlyphString glyphString = iterator.next(); - glyphString.destroy(gl, rs); - } - stringCacheMap.clear(); - stringCacheArray.clear(); - } */ - - public void destroy(GL2ES2 gl) { - // fluchCache(gl) already called - final Iterator iterator = stringCacheMap.values().iterator(); - while(iterator.hasNext()){ - final GLRegion region = iterator.next(); - region.destroy(gl, renderer); - } - stringCacheMap.clear(); - stringCacheArray.clear(); - } - - /** - *

Sets the cache limit for reusing GlyphString's and their Region. - * Default is {@link #DEFAULT_CACHE_LIMIT}, -1 unlimited, 0 turns cache off, >0 limited

- * - *

The cache will be validate when the next string rendering happens.

- * - * @param newLimit new cache size - * - * @see #DEFAULT_CACHE_LIMIT - */ - public final void setCacheLimit(int newLimit ) { stringCacheLimit = newLimit; } - - /** - * Sets the cache limit, see {@link #setCacheLimit(int)} and validates the cache. - * - * @see #setCacheLimit(int) - * - * @param gl current GL used to remove cached objects if required - * @param newLimit new cache size - */ - public final void setCacheLimit(GL2ES2 gl, int newLimit ) { stringCacheLimit = newLimit; validateCache(gl, 0); } - - /** - * @return the current cache limit - */ - public final int getCacheLimit() { return stringCacheLimit; } - - /** - * @return the current utilized cache size, <= {@link #getCacheLimit()} - */ - public final int getCacheSize() { return stringCacheArray.size(); } - - protected final void validateCache(GL2ES2 gl, int space) { - if ( getCacheLimit() > 0 ) { - while ( getCacheSize() + space > getCacheLimit() ) { - removeCachedRegion(gl, 0); - } - } - } - - protected final GLRegion getCachedRegion(Font font, CharSequence str, int fontSize) { - return stringCacheMap.get(getKey(font, str, fontSize)); - } - - protected final void addCachedRegion(GL2ES2 gl, Font font, CharSequence str, int fontSize, GLRegion glyphString) { - if ( 0 != getCacheLimit() ) { - final String key = getKey(font, str, fontSize); - final GLRegion oldRegion = stringCacheMap.put(key, glyphString); - if ( null == oldRegion ) { - // new entry .. - validateCache(gl, 1); - stringCacheArray.add(stringCacheArray.size(), key); - } /// else overwrite is nop .. - } - } - - protected final void removeCachedRegion(GL2ES2 gl, Font font, CharSequence str, int fontSize) { - final String key = getKey(font, str, fontSize); - GLRegion region = stringCacheMap.remove(key); - if(null != region) { - region.destroy(gl, renderer); - } - stringCacheArray.remove(key); - } - - protected final void removeCachedRegion(GL2ES2 gl, int idx) { - final String key = stringCacheArray.remove(idx); - final GLRegion region = stringCacheMap.remove(key); - if(null != region) { - region.destroy(gl, renderer); - } - } - - protected final String getKey(Font font, CharSequence str, int fontSize) { - final StringBuilder sb = new StringBuilder(); - return font.getName(sb, Font.NAME_UNIQUNAME) - .append(".").append(str.hashCode()).append(".").append(fontSize).toString(); - } - - /** Default cache limit, see {@link #setCacheLimit(int)} */ - public static final int DEFAULT_CACHE_LIMIT = 256; - - private final HashMap stringCacheMap = new HashMap(DEFAULT_CACHE_LIMIT); - private final ArrayList stringCacheArray = new ArrayList(DEFAULT_CACHE_LIMIT); - private int stringCacheLimit = DEFAULT_CACHE_LIMIT; -} \ No newline at end of file diff --git a/src/jogl/classes/com/jogamp/graph/font/Font.java b/src/jogl/classes/com/jogamp/graph/font/Font.java index afffe0654..122015218 100644 --- a/src/jogl/classes/com/jogamp/graph/font/Font.java +++ b/src/jogl/classes/com/jogamp/graph/font/Font.java @@ -73,6 +73,9 @@ public interface Font { /** * Glyph for font + * + * http://developer.apple.com/textfonts/TTRefMan/RM06/Chap6cmap.html + * http://developer.apple.com/textfonts/TTRefMan/RM06/Chap6glyf.html */ public interface Glyph { // reserved special glyph IDs @@ -103,11 +106,12 @@ public interface Font { public StringBuilder getAllNames(StringBuilder string, String separator); - public float getAdvanceWidth(int i, float pixelSize); + public float getAdvanceWidth(int glyphID, float pixelSize); public Metrics getMetrics(); public Glyph getGlyph(char symbol); public int getNumGlyphs(); + public float getLineHeight(float pixelSize); public float getStringWidth(CharSequence string, float pixelSize); public float getStringHeight(CharSequence string, float pixelSize); public AABBox getStringBounds(CharSequence string, float pixelSize); diff --git a/src/jogl/classes/jogamp/graph/font/typecast/TypecastFont.java b/src/jogl/classes/jogamp/graph/font/typecast/TypecastFont.java index 81c06cd83..8dd9ce4d7 100644 --- a/src/jogl/classes/jogamp/graph/font/typecast/TypecastFont.java +++ b/src/jogl/classes/jogamp/graph/font/typecast/TypecastFont.java @@ -166,8 +166,8 @@ class TypecastFont implements Font { } @Override - public float getAdvanceWidth(int i, float pixelSize) { - return font.getHmtxTable().getAdvanceWidth(i) * metrics.getScale(pixelSize); + public float getAdvanceWidth(int glyphID, float pixelSize) { + return font.getHmtxTable().getAdvanceWidth(glyphID) * metrics.getScale(pixelSize); } @Override @@ -197,7 +197,7 @@ class TypecastFont implements Font { if(null == glyph) { throw new RuntimeException("Could not retrieve glyph for symbol: <"+symbol+"> "+(int)symbol+" -> glyph id "+code); } - final OutlineShape shape = TypecastRenderer.buildShape(glyph, vertexFactory); + final OutlineShape shape = TypecastRenderer.buildShape(symbol, glyph, vertexFactory); result = new TypecastGlyph(this, symbol, code, glyph.getBBox(), glyph.getAdvanceWidth(), shape); if(DEBUG) { System.err.println("New glyph: " + (int)symbol + " ( " + symbol +" ) -> " + code + ", contours " + glyph.getPointCount() + ": " + shape); @@ -221,13 +221,22 @@ class TypecastFont implements Font { return result; } + @Override + public float getLineHeight(float pixelSize) { + final Metrics metrics = getMetrics(); + final float lineGap = metrics.getLineGap(pixelSize) ; // negative value! + final float ascent = metrics.getAscent(pixelSize) ; // negative value! + final float descent = metrics.getDescent(pixelSize) ; // positive value! + final float advanceY = lineGap - descent + ascent; // negative value! + return -advanceY; + } + @Override public float getStringWidth(CharSequence string, float pixelSize) { float width = 0; final int len = string.length(); - for (int i=0; i< len; i++) - { - char character = string.charAt(i); + for (int i=0; i< len; i++) { + final char character = string.charAt(i); if (character == '\n') { width = 0; } else { @@ -235,7 +244,6 @@ class TypecastFont implements Font { width += glyph.getAdvance(pixelSize, false); } } - return (int)(width + 0.5f); } @@ -243,12 +251,10 @@ class TypecastFont implements Font { public float getStringHeight(CharSequence string, float pixelSize) { int height = 0; - for (int i=0; i 0) { - totalHeight -= advanceY; + totalHeight += lineHeight; totalWidth = Math.max(curLineWidth, totalWidth); } return new AABBox(0, 0, 0, totalWidth, totalHeight,0); -- cgit v1.2.3