diff options
17 files changed, 443 insertions, 265 deletions
diff --git a/make/scripts/tests.sh b/make/scripts/tests.sh index ed1f17a41..d9116b16b 100644 --- a/make/scripts/tests.sh +++ b/make/scripts/tests.sh @@ -932,12 +932,12 @@ function testawtswt() { # #testnoawt com.jogamp.opengl.test.junit.graph.TestRegionRendererNEWT01 $* #testnoawt com.jogamp.opengl.test.junit.graph.TestTextRendererNEWT00 $* -#testnoawt com.jogamp.opengl.test.junit.graph.TestTextRendererNEWT01 $* #testnoawt com.jogamp.opengl.test.junit.graph.TestTextRendererNEWT10 $* #testnoawt com.jogamp.opengl.test.junit.graph.TestFontsNEWT00 $* #testnoawt com.jogamp.opengl.test.junit.graph.TestTextRendererNEWTBugXXXX $* #testnoawt com.jogamp.opengl.test.junit.graph.demos.ui.UINewtDemo01 $* -testnoawt com.jogamp.opengl.test.junit.graph.demos.GPUTextNewtDemo $* +#testnoawt com.jogamp.opengl.test.junit.graph.demos.GPUTextNewtDemo $* +testnoawt com.jogamp.opengl.test.junit.graph.TestTextRendererNEWT01 $* #testnoawt com.jogamp.opengl.test.junit.graph.demos.GPURegionNewtDemo $* #testnoawt com.jogamp.opengl.test.junit.graph.demos.GPUUISceneNewtDemo $* #testawt com.jogamp.opengl.test.junit.graph.demos.GPUUISceneNewtCanvasAWTDemo $* diff --git a/src/jogl/classes/com/jogamp/graph/curve/opengl/TextRegionUtil.java b/src/jogl/classes/com/jogamp/graph/curve/opengl/TextRegionUtil.java index 5aa2be258..a4ba4bf52 100644 --- a/src/jogl/classes/com/jogamp/graph/curve/opengl/TextRegionUtil.java +++ b/src/jogl/classes/com/jogamp/graph/curve/opengl/TextRegionUtil.java @@ -89,25 +89,21 @@ public class TextRegionUtil { final int charCount = str.length(); // region.setFlipped(true); - final Font.Metrics metrics = font.getMetrics(); final int lineHeight = font.getLineHeightFU(); int y = 0; int advanceTotal = 0; - char left_character = 0; - int left_glyphid = 0; + Font.Glyph left_glyph = null; for(int i=0; i< charCount; i++) { final char character = str.charAt(i); if( '\n' == character ) { y -= lineHeight; advanceTotal = 0; - left_glyphid = 0; - left_character = 0; + left_glyph = null; } else if (character == ' ') { advanceTotal += font.getAdvanceWidthFU(Glyph.ID_SPACE); - left_glyphid = 0; - left_character = character; + left_glyph = null; } else { // reset transform if( null != transform ) { @@ -115,27 +111,20 @@ public class TextRegionUtil { } else { temp1.setToIdentity(); } - temp1.translate(advanceTotal, y, temp2); - final Font.Glyph glyph = font.getGlyph(character); final OutlineShape glyphShape = glyph.getShape(); if( null == glyphShape ) { - left_glyphid = 0; + left_glyph = null; + temp1.translate(advanceTotal, y, temp2); continue; } - visitor.visit(glyphShape, temp1); - final int right_glyphid = glyph.getID(); - final int kern = font.getKerningFU(left_glyphid, right_glyphid); - final int advance = glyph.getAdvanceFU(); - advanceTotal += advance + kern; - if( Region.DEBUG_INSTANCE && 0 != left_character && kern > 0f ) { - System.err.println(": '"+left_character+"'/"+left_glyphid+" -> '"+character+"'/"+right_glyphid+ - ": a "+advance+"px + k ["+kern+"em, "+kern+"px = "+(advance+kern)+"px -> "+advanceTotal+"px, y "+y); + if( null != left_glyph ) { + advanceTotal += left_glyph.getKerningFU(glyph.getID()); } - // advanceTotal += glyph.getAdvance(pixelSize, true) - // + font.getKerning(left_glyphid, right_glyphid); - left_glyphid = right_glyphid; - left_character = character; + temp1.translate(advanceTotal, y, temp2); + visitor.visit(glyphShape, temp1); + advanceTotal += glyph.getAdvanceFU(); + left_glyph = glyph; } } } @@ -351,7 +340,7 @@ public class TextRegionUtil { protected final String getKey(final Font font, final CharSequence str, final int special) { final StringBuilder sb = new StringBuilder(); - return font.getName(sb, Font.NAME_UNIQUNAME) + return sb.append( font.getName(Font.NAME_UNIQUNAME) ) .append(".").append(str.hashCode()).append(".").append(special).toString(); } diff --git a/src/jogl/classes/com/jogamp/graph/font/Font.java b/src/jogl/classes/com/jogamp/graph/font/Font.java index 9f25b5481..5c63227b3 100644 --- a/src/jogl/classes/com/jogamp/graph/font/Font.java +++ b/src/jogl/classes/com/jogamp/graph/font/Font.java @@ -144,6 +144,8 @@ public interface Font { Font getFont(); char getSymbol(); + + /** Return this glyph's ID */ int getID(); /** @@ -188,20 +190,49 @@ public interface Font { */ float getAdvance(final float pixelSize); + /** True if kerning values are horizontal, otherwise vertical */ + boolean isKerningHorizontal(); + /** True if kerning values are perpendicular to text flow, otherwise along with flow */ + boolean isKerningCrossstream(); + + /** Return the number of kerning values stored for this glyph, associated to a right hand glyph. */ + int getKerningPairCount(); + + /** + * Returns the optional kerning inter-glyph distance within words between this glyph and the given right glyph_id in font-units to be divided by unitsPerEM + * + * @param right_glyphid right glyph code id + * @return font-units to be divided by unitsPerEM + */ + int getKerningFU(final int right_glyphid); + + /** + * Returns the optional kerning inter-glyph distance within words between this glyph and the given right glyph_id in fractional font em-size [0..1]. + * + * @param right_glyphid right glyph code id + * @return fractional font em-size distance [0..1] + */ + float getKerning(final int right_glyphid); + OutlineShape getShape(); @Override int hashCode(); + + @Override + String toString(); + + /** Return all glyph details as string. */ + String fullString(); } String getName(final int nameIndex); - StringBuilder getName(final StringBuilder string, final int nameIndex); /** Shall return the family and subfamily name, separated a dash. * <p>{@link #getName(StringBuilder, int)} w/ {@link #NAME_FAMILY} and {@link #NAME_SUBFAMILY}</p> * <p>Example: "{@code Ubuntu-Regular}"</p> */ - StringBuilder getFullFamilyName(final StringBuilder buffer); + String getFullFamilyName(); StringBuilder getAllNames(final StringBuilder string, final String separator); @@ -225,27 +256,12 @@ public interface Font { */ int getAdvanceWidthFU(final int glyphID); - /** - * Returns the optional kerning inter-glyph distance within words in fractional font em-size [0..1]. - * - * @param left_glyphid left glyph code id - * @param right_glyphid right glyph code id - * @return fractional font em-size distance [0..1] - */ - float getKerning(final int left_glyphid, final int right_glyphid); - - /** - * Returns the optional kerning inter-glyph distance within words in fractional font-units to be divided by unitsPerEM - * - * @param left_glyphid left glyph code id - * @param right_glyphid right glyph code id - * @return font-units to be divided by unitsPerEM - */ - int getKerningFU(final int left_glyphid, final int right_glyphid); - Metrics getMetrics(); + int getGlyphID(final char symbol); + Glyph getGlyph(final char symbol); + int getNumGlyphs(); /** diff --git a/src/jogl/classes/jogamp/graph/font/typecast/TypecastFont.java b/src/jogl/classes/jogamp/graph/font/typecast/TypecastFont.java index 885261bf9..146bc0380 100644 --- a/src/jogl/classes/jogamp/graph/font/typecast/TypecastFont.java +++ b/src/jogl/classes/jogamp/graph/font/typecast/TypecastFont.java @@ -27,13 +27,14 @@ */ package jogamp.graph.font.typecast; -import jogamp.graph.font.typecast.ot.OTFont; import jogamp.graph.font.typecast.ot.OTFontCollection; +import jogamp.graph.font.typecast.ot.TTFont; import jogamp.graph.font.typecast.ot.table.CmapFormat; import jogamp.graph.font.typecast.ot.table.CmapIndexEntry; import jogamp.graph.font.typecast.ot.table.CmapTable; import jogamp.graph.font.typecast.ot.table.HdmxTable; import jogamp.graph.font.typecast.ot.table.ID; +import jogamp.graph.font.typecast.ot.table.KernSubtable; import jogamp.graph.font.typecast.ot.table.KernSubtableFormat0; import jogamp.graph.font.typecast.ot.table.KernTable; import jogamp.graph.font.typecast.ot.table.KerningPair; @@ -54,7 +55,7 @@ class TypecastFont implements Font { private static final Vertex.Factory<SVertex> vertexFactory = SVertex.factory(); // private final OTFontCollection fontset; - /* pp */ final OTFont font; + /* pp */ final TTFont font; private final CmapFormat cmapFormat; private final int cmapentries; private final IntObjectHashMap char2Glyph; @@ -153,22 +154,16 @@ class TypecastFont implements Font { } @Override - public StringBuilder getName(final StringBuilder sb, final int nameIndex) { - return font.getName(nameIndex, sb); - } - @Override public String getName(final int nameIndex) { - return getName(null, nameIndex).toString(); + return font.getName(nameIndex); } @Override public StringBuilder getAllNames(final StringBuilder sb, final String separator) { return font.getAllNames(sb, separator); } @Override - public StringBuilder getFullFamilyName(StringBuilder sb) { - sb = getName(sb, Font.NAME_FAMILY).append("-"); - getName(sb, Font.NAME_SUBFAMILY); - return sb; + public String getFullFamilyName() { + return getName(Font.NAME_FAMILY) + "-" + getName(Font.NAME_SUBFAMILY); } @Override @@ -190,34 +185,6 @@ class TypecastFont implements Font { } @Override - public final float getKerning(final int left_glyphid, final int right_glyphid) { - return metrics.getScale( getKerningFU(left_glyphid, right_glyphid) ); - } - - @Override - public int getKerningFU(final int left_glyphid, final int right_glyphid) { - if( 0 == left_glyphid || 0 == right_glyphid ) { - return 0; - } - final KernTable kern = font.getKernTable(); - if (kern != null) { - final int kernSubtableCount = kern.getSubtableCount(); - if( 0 < kernSubtableCount ) { - final KernSubtableFormat0 kst0 = kern.getSubtable0(); - if( null != kst0 && kst0.areKerningValues() && kst0.isHorizontal() && !kst0.isCrossstream() ) { - for (int i = 0; i < kst0.getKerningPairCount(); i++) { - final KerningPair kpair = kst0.getKerningPair(i); - if( kpair.getLeft() == left_glyphid && kpair.getRight() == right_glyphid ) { - return kpair.getValue(); - } - } - } - } - } - return 0; - } - - @Override public int getGlyphID(final char symbol) { // enforce mapping as some fonts have an erroneous cmap (FreeSerif-Regular) switch(symbol) { @@ -241,7 +208,7 @@ class TypecastFont implements Font { if (null == result) { final int glyph_id = getGlyphID( symbol ); - jogamp.graph.font.typecast.ot.OTGlyph glyph = font.getGlyph(glyph_id); + jogamp.graph.font.typecast.ot.Glyph glyph = font.getGlyph(glyph_id); final int glyph_advance; final AABBox glyph_bbox; if(null == glyph) { @@ -264,7 +231,14 @@ class TypecastFont implements Font { throw new RuntimeException("Could not retrieve glyph for symbol: <"+symbol+"> "+(int)symbol+" -> glyph id "+glyph_id); } final OutlineShape shape = TypecastRenderer.buildShape(symbol, glyph, vertexFactory); - result = new TypecastGlyph(this, symbol, glyph_id, glyph_bbox, glyph_advance, shape); + KernSubtable kernSub = null; + { + final KernTable kern = font.getKernTable(); + if (kern != null ) { + kernSub = kern.getSubtable0(); + } + } + result = new TypecastGlyph(this, symbol, glyph_id, glyph_bbox, glyph_advance, kernSub, shape); if(DEBUG) { final PostTable post = font.getPostTable(); final String glyph_name = null != post ? post.getGlyphName(glyph_id) : "n/a"; @@ -557,9 +531,10 @@ class TypecastFont implements Font { @Override public String toString() { - return getFullFamilyName(null).toString(); + return getFullFamilyName(); } + @SuppressWarnings("unused") @Override public String fullString() { final StringBuilder sb = new StringBuilder(); @@ -569,7 +544,7 @@ class TypecastFont implements Font { if( null != font.getVheaTable() ) { sb.append("\n\n").append(font.getVheaTable()); } - if( null != font.getKernTable() ) { + if( false && null != font.getKernTable() ) { // too long final PostTable post = font.getPostTable(); final KernTable kern = font.getKernTable(); sb.append("\n\n").append(kern); diff --git a/src/jogl/classes/jogamp/graph/font/typecast/TypecastFontConstructor.java b/src/jogl/classes/jogamp/graph/font/typecast/TypecastFontConstructor.java index ef7f38e64..72dd95da2 100644 --- a/src/jogl/classes/jogamp/graph/font/typecast/TypecastFontConstructor.java +++ b/src/jogl/classes/jogamp/graph/font/typecast/TypecastFontConstructor.java @@ -40,11 +40,11 @@ public class TypecastFontConstructor implements FontConstructor { @Override public Font create(final File ffile) throws IOException { - return new TypecastFont( OTFontCollection.create(ffile) ); + return new TypecastFont( new OTFontCollection(ffile) ); } @Override public Font create(final InputStream istream, final int streamLen) throws IOException { - return new TypecastFont( OTFontCollection.create(istream, streamLen) ); + return new TypecastFont( new OTFontCollection(istream, streamLen) ); } } diff --git a/src/jogl/classes/jogamp/graph/font/typecast/TypecastGlyph.java b/src/jogl/classes/jogamp/graph/font/typecast/TypecastGlyph.java index b36196ee5..b5876758f 100644 --- a/src/jogl/classes/jogamp/graph/font/typecast/TypecastGlyph.java +++ b/src/jogl/classes/jogamp/graph/font/typecast/TypecastGlyph.java @@ -32,6 +32,8 @@ import com.jogamp.graph.curve.OutlineShape; import com.jogamp.graph.font.Font; import com.jogamp.opengl.math.geom.AABBox; +import jogamp.graph.font.typecast.ot.table.KernSubtable; +import jogamp.graph.font.typecast.ot.table.KerningPair; import jogamp.graph.font.typecast.ot.table.PostTable; public final class TypecastGlyph implements Font.Glyph { @@ -170,9 +172,36 @@ public final class TypecastGlyph implements Font.Glyph { public static final short INVALID_ID = (short)((1 << 16) - 1); public static final short MAX_ID = (short)((1 << 16) - 2); + private static int[][] growPairArray(final int[][] src) { + final int length = src.length; + final int new_length = length * 2; + final int[/*right_glyphid*/][/*value*/] dst = new int[new_length][2]; + for (int i = 0; i < length; i++) { + dst[i][0] = src[i][0]; + dst[i][1] = src[i][1]; + } + return dst; + } + + private static int[][] trimPairArray(final int[][] src, final int new_length) { + final int length = src.length; + if( new_length >= length ) { + return src; + } + final int[/*right_glyphid*/][/*value*/] dst = new int[new_length][2]; + for (int i = 0; i < new_length; i++) { + dst[i][0] = src[i][0]; + dst[i][1] = src[i][1]; + } + return dst; + } + private final char symbol; - private final OutlineShape shape; // in EM units private final int id; + private final int[/*right_glyphid*/][/*value*/] kerning; + private final boolean kerning_horizontal; + private final boolean kerning_crossstream; + private final OutlineShape shape; // in EM units private final Metrics metrics; /** @@ -184,10 +213,37 @@ public final class TypecastGlyph implements Font.Glyph { * @param advance from hmtx in font-units * @param shape */ - protected TypecastGlyph(final TypecastFont font, final char symbol, final int id, final AABBox bbox, final int advance, final OutlineShape shape) { + protected TypecastGlyph(final TypecastFont font, final char symbol, final int id, final AABBox bbox, final int advance, + final KernSubtable kernSub, final OutlineShape shape) { this.symbol = symbol; - this.shape = shape; this.id = id; + if( null != kernSub && kernSub.areKerningValues() ) { + int pair_sz = 64; + int pair_idx = 0; + int[/*right_glyphid*/][/*value*/] pairs = new int[pair_sz][2]; + for (int i = 0; i < kernSub.getKerningPairCount(); i++) { + final KerningPair kpair = kernSub.getKerningPair(i); + if( kpair.getLeft() == id ) { + if( pair_idx == pair_sz ) { + pairs = growPairArray(pairs); + pair_sz = pairs.length; + } + pairs[pair_idx][0] = kpair.getRight(); + pairs[pair_idx][1] = kpair.getValue(); + ++pair_idx; + } else if( kpair.getLeft() > id ) { + break; // early out + } + } + this.kerning = trimPairArray(pairs, pair_idx); + this.kerning_horizontal = kernSub.isHorizontal(); + this.kerning_crossstream = kernSub.isCrossstream(); + } else { + this.kerning = new int[0][0]; + this.kerning_horizontal = true; + this.kerning_crossstream = true; + } + this.shape = shape; this.metrics = new Metrics(font, bbox, advance); } @@ -248,6 +304,39 @@ public final class TypecastGlyph implements Font.Glyph { } @Override + public final boolean isKerningHorizontal() { return kerning_horizontal; } + + @Override + public final boolean isKerningCrossstream() { return kerning_crossstream; } + + @Override + public final int getKerningPairCount() { return kerning.length; } + + @Override + public final int getKerningFU(final int right_glyphid) { + // binary search in ordered kerning table + int l = 0; + int h = kerning.length-1; + while( l <= h ) { + final int i = ( l + h ) / 2; + final int k_right = kerning[i][0]; + if ( k_right < right_glyphid ) { + l = i + 1; + } else if ( k_right > right_glyphid ) { + h = i - 1; + } else { + return kerning[i][1]; + } + } + return 0; + } + + @Override + public final float getKerning(final int right_glyphid) { + return getScale( getKerningFU(right_glyphid) ); + } + + @Override public final OutlineShape getShape() { return this.shape; } @@ -263,10 +352,38 @@ public final class TypecastGlyph implements Font.Glyph { public String toString() { final PostTable post = metrics.getFont().getPostTable(); final String glyph_name = null != post ? post.getGlyphName(id) : "n/a"; - return new StringBuilder() - .append("Glyph id ").append(id).append(" '").append(glyph_name).append("'") - .append(", advance ").append(getAdvanceFU()) - .append(", ").append(getBBoxFU()) - .toString(); + final StringBuilder sb = new StringBuilder(); + sb.append("Glyph id ").append(id).append(" '").append(glyph_name).append("'") + .append(", advance ").append(getAdvanceFU()) + .append(", kerning[size ").append(kerning.length).append(", horiz ").append(this.isKerningHorizontal()).append(", cross ").append(this.isKerningCrossstream()).append("]"); + return sb.toString(); + } + + @Override + public String fullString() { + final PostTable post = metrics.getFont().getPostTable(); + final String glyph_name = null != post ? post.getGlyphName(id) : "n/a"; + final StringBuilder sb = new StringBuilder(); + sb.append("Glyph id ").append(id).append(" '").append(glyph_name).append("'") + .append(", advance ").append(getAdvanceFU()) + .append(", ").append(getBBoxFU()); + + sb.append("\n Kerning: size ").append(kerning.length).append(", horiz ").append(this.isKerningHorizontal()).append(", cross ").append(this.isKerningCrossstream()); + final int left = getID(); + for (int i = 0; i < kerning.length; i++) { + final int right = kerning[i][0]; + final int value = kerning[i][1]; + final String leftS; + final String rightS; + if( null == post ) { + leftS = String.valueOf(left); + rightS = String.valueOf(left); + } else { + leftS = post.getGlyphName(left)+"/"+String.valueOf(left); + rightS = post.getGlyphName(right)+"/"+String.valueOf(right); + } + sb.append("\n kp[").append(i).append("]: ").append(leftS).append(" -> ").append(rightS).append(" = ").append(value); + } + return sb.toString(); } } diff --git a/src/jogl/classes/jogamp/graph/font/typecast/TypecastRenderer.java b/src/jogl/classes/jogamp/graph/font/typecast/TypecastRenderer.java index 09a63d845..472e3e58e 100644 --- a/src/jogl/classes/jogamp/graph/font/typecast/TypecastRenderer.java +++ b/src/jogl/classes/jogamp/graph/font/typecast/TypecastRenderer.java @@ -27,7 +27,6 @@ */ package jogamp.graph.font.typecast; -import jogamp.graph.font.typecast.ot.OTGlyph; import jogamp.graph.font.typecast.ot.Point; import jogamp.opengl.Debug; @@ -76,7 +75,7 @@ public class TypecastRenderer { shape.addVertex(0, p3.x, p3.y, p3.onCurve); } */ - public static OutlineShape buildShape(final char symbol, final OTGlyph glyph, final Factory<? extends Vertex> vertexFactory) { + public static OutlineShape buildShape(final char symbol, final jogamp.graph.font.typecast.ot.Glyph glyph, final Factory<? extends Vertex> vertexFactory) { // // See Typecast: GlyphPathFactory.addContourToPath(..) // @@ -111,7 +110,7 @@ public class TypecastRenderer { } } */ - private static void buildShapeImpl(final OutlineShape shape, final char symbol, final OTGlyph glyph) { + private static void buildShapeImpl(final OutlineShape shape, final char symbol, final jogamp.graph.font.typecast.ot.Glyph glyph) { // Iterate through all of the points in the glyph. Each time we find a // contour end point, add the point range to the path. int startIndex = 0; diff --git a/src/test/com/jogamp/opengl/test/junit/graph/TestFontsNEWT00.java b/src/test/com/jogamp/opengl/test/junit/graph/TestFontsNEWT00.java index 9592a06cf..8a2284b67 100644 --- a/src/test/com/jogamp/opengl/test/junit/graph/TestFontsNEWT00.java +++ b/src/test/com/jogamp/opengl/test/junit/graph/TestFontsNEWT00.java @@ -36,7 +36,6 @@ import org.junit.runners.MethodSorters; import com.jogamp.graph.font.Font; import com.jogamp.graph.font.FontScale; -import com.jogamp.graph.font.Font.Glyph; import com.jogamp.opengl.math.FloatUtil; import com.jogamp.opengl.math.geom.AABBox; import com.jogamp.opengl.test.junit.util.UITestCase; @@ -67,14 +66,21 @@ public class TestFontsNEWT00 extends UITestCase { final float dpi = 96; for(int i=0; i<fonts.length; i++) { final Font font = fonts[i]; + System.err.println("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); + System.err.println(font.getAllNames(null, "\n")); + System.err.println("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); final float pixelSize = FontScale.toPixels(fontSize, dpi); - System.err.println(font.getFullFamilyName(null).toString()+": "+fontSize+"p, "+dpi+"dpi -> "+pixelSize+"px:"); - testFontGlyphAdvancedSize(font, 'X', pixelSize); - testFontGlyphAdvancedSize(font, 'j', pixelSize); - testFontGlyphAdvancedSize(font, ' ', pixelSize); + System.err.println(font.getFullFamilyName()+": "+fontSize+"p, "+dpi+"dpi -> "+pixelSize+"px:"); + System.err.println(font.fullString()); + testFontGlyph01(font, 'X', pixelSize); + testFontGlyph01(font, 'j', pixelSize); + testFontGlyph01(font, ' ', pixelSize); + testFontGlyph02(font, 'X', 'X'); + testFontGlyph02(font, 't', '.'); + testFontGlyph02(font, 'f', 'f'); } } - void testFontGlyphAdvancedSize(final Font font, final char c, final float pixelSize) { + void testFontGlyph01(final Font font, final char c, final float pixelSize) { final int glyphID = font.getGlyphID(c); final int s0 = font.getAdvanceWidthFU(glyphID); final Font.Glyph glyph = font.getGlyph(c); @@ -108,4 +114,18 @@ public class TestFontsNEWT00 extends UITestCase { Assert.assertEquals(s1_em*pixelSize, s1_px, FloatUtil.EPSILON); Assert.assertEquals(s0_px, s1_px, FloatUtil.EPSILON); } + void testFontGlyph02(final Font font, final char left, final char right) { + final int glyphid_left = font.getGlyphID(left); + final int glyphid_right = font.getGlyphID(right); + final Font.Glyph glyph_left = font.getGlyph(left); + final Font.Glyph glyph_right = font.getGlyph(right); + + final int k_val = glyph_left.getKerningFU(glyphid_right); + + System.err.println(" Font "+font.getFullFamilyName()); + System.err.println(" Char left['"+left+"', id "+glyphid_left+", kpairs "+glyph_left.getKerningPairCount()+ + "], right['"+right+"', id "+glyphid_right+"], kerning "+k_val); + System.err.println(" "+glyph_left); + // System.err.println(" "+glyph_left.fullString()); + } } diff --git a/src/test/com/jogamp/opengl/test/junit/graph/TestTextRendererNEWT00.java b/src/test/com/jogamp/opengl/test/junit/graph/TestTextRendererNEWT00.java index 9cb29365c..c5fe0b903 100644 --- a/src/test/com/jogamp/opengl/test/junit/graph/TestTextRendererNEWT00.java +++ b/src/test/com/jogamp/opengl/test/junit/graph/TestTextRendererNEWT00.java @@ -366,10 +366,9 @@ public class TestTextRendererNEWT00 extends UITestCase { } String getFontInfo() { - final float unitsPerEM_Inv = font.getMetrics().getScale(1f); - final float unitsPerEM = 1f / unitsPerEM_Inv; + final float unitsPerEM = font.getMetrics().getUnitsPerEM(); return String.format("Font %s%n %s%nunitsPerEM %f (upem)", - font.getFullFamilyName(null).toString(), + font.getFullFamilyName(), font.getName(Font.NAME_UNIQUNAME), unitsPerEM); } diff --git a/src/test/com/jogamp/opengl/test/junit/graph/TestTextRendererNEWT01.java b/src/test/com/jogamp/opengl/test/junit/graph/TestTextRendererNEWT01.java index 305e12f27..6211409f7 100644 --- a/src/test/com/jogamp/opengl/test/junit/graph/TestTextRendererNEWT01.java +++ b/src/test/com/jogamp/opengl/test/junit/graph/TestTextRendererNEWT01.java @@ -36,6 +36,7 @@ import com.jogamp.opengl.GLCapabilities; import com.jogamp.opengl.GLCapabilitiesImmutable; import com.jogamp.opengl.GLException; import com.jogamp.opengl.GLProfile; +import com.jogamp.opengl.math.geom.AABBox; import jogamp.common.os.PlatformPropsImpl; @@ -48,6 +49,7 @@ import com.jogamp.common.os.Platform; import com.jogamp.graph.curve.Region; import com.jogamp.graph.curve.opengl.RenderState; import com.jogamp.graph.font.FontFactory; +import com.jogamp.graph.font.FontSet; import com.jogamp.graph.geom.SVertex; import com.jogamp.newt.opengl.GLWindow; import com.jogamp.opengl.test.junit.graph.demos.GPUTextRendererListenerBase01; @@ -104,7 +106,7 @@ public class TestTextRendererNEWT01 extends UITestCase { } @Test - public void testTextRendererR2T01() throws InterruptedException { + public void testTextRendererR2T01() throws InterruptedException, GLException, IOException { if(Platform.CPUFamily.X86 != PlatformPropsImpl.CPU_ARCH.family) { // FIXME // FIXME: Disabled for now - since it doesn't seem fit for mobile (performance wise). System.err.println("disabled on non desktop (x86) arch for now .."); @@ -124,42 +126,68 @@ public class TestTextRendererNEWT01 extends UITestCase { final TextGLListener textGLListener = new TextGLListener(rs, Region.VBAA_RENDERING_BIT, 4 /* sampleCount */, DEBUG, TRACE); textGLListener.attachInputListenerTo(window); window.addGLEventListener(textGLListener); + textGLListener.setHeadBox(2, true); + window.display(); + // final AABBox headbox = textGLListener.getHeadBox(); + // GPUTextRendererListenerBase01.upsizeWindowSurface(window, false, (int)(headbox.getWidth()*1.5f), (int)(headbox.getHeight()*2f)); + + final Runnable action_per_font = new Runnable() { + @Override + public void run() { + textGLListener.setHeadBox(1, false); + textGLListener.setSampleCount(2); + window.display(); + textGLListener.printScreenOnGLThread(window, "./", window.getTitle(), "", false); + sleep(); + + textGLListener.setHeadBox(2, false); + textGLListener.setSampleCount(2); + window.display(); + textGLListener.printScreenOnGLThread(window, "./", window.getTitle(), "", false); + sleep(); + + textGLListener.setHeadBox(1, false); + textGLListener.setSampleCount(3); + window.display(); + textGLListener.printScreenOnGLThread(window, "./", window.getTitle(), "", false); + sleep(); + + textGLListener.setHeadBox(2, false); + textGLListener.setSampleCount(3); + window.display(); + textGLListener.printScreenOnGLThread(window, "./", window.getTitle(), "", false); + sleep(); + + textGLListener.setHeadBox(1, false); + textGLListener.setSampleCount(4); + window.display(); + textGLListener.printScreenOnGLThread(window, "./", window.getTitle(), "", false); + sleep(); + + textGLListener.setHeadBox(2, false); + textGLListener.setSampleCount(4); + window.display(); + textGLListener.printScreenOnGLThread(window, "./", window.getTitle(), "", false); + sleep(); + } }; + + if(textGLListener.setFontSet(FontFactory.UBUNTU, FontSet.FAMILY_LIGHT, FontSet.STYLE_NONE)) { + action_per_font.run(); + } - if(textGLListener.setFontSet(FontFactory.UBUNTU, 0, 0)) { - textGLListener.setTech(-400, -30, 0f, -1000, 2); - window.display(); - window.display(); - sleep(); - - textGLListener.setTech(-400, -30, 0f, -380, 3); - window.display(); - sleep(); - - textGLListener.setTech(-400, -20, 0f, -80, 4); - window.display(); - sleep(); + if(textGLListener.setFontSet(FontFactory.UBUNTU, FontSet.FAMILY_REGULAR, FontSet.STYLE_NONE)) { + action_per_font.run(); } if(textGLListener.setFontSet(FontFactory.JAVA, 0, 0)) { - textGLListener.setTech(-400, -30, 0f, -1000, 2); - window.display(); - window.display(); - sleep(); - - textGLListener.setTech(-400, -30, 0f, -380, 3); - window.display(); - sleep(); - - textGLListener.setTech(-400, -20, 0f, -80, 4); - window.display(); - sleep(); + action_per_font.run(); } destroyWindow(window); } @Test - public void testTextRendererMSAA01() throws InterruptedException { + public void testTextRendererMSAA01() throws InterruptedException, GLException, IOException { final GLProfile glp = GLProfile.get(GLProfile.GL2ES2); final GLCapabilities caps = new GLCapabilities(glp); caps.setAlphaBits(4); @@ -175,43 +203,41 @@ public class TestTextRendererNEWT01 extends UITestCase { final TextGLListener textGLListener = new TextGLListener(rs, 0, 0 /* sampleCount */, DEBUG, TRACE); textGLListener.attachInputListenerTo(window); window.addGLEventListener(textGLListener); + textGLListener.setHeadBox(2, true); + window.display(); - if(textGLListener.setFontSet(FontFactory.UBUNTU, 0, 0)) { - textGLListener.setTech(-400, -30, 0f, -1000, 0); - window.display(); - window.display(); - sleep(); - - textGLListener.setTech(-400, -30, 0, -380, 0); - window.display(); - sleep(); + final Runnable action_per_font = new Runnable() { + @Override + public void run() { + textGLListener.setHeadBox(1, false); + textGLListener.setSampleCount(0); + window.display(); + textGLListener.printScreenOnGLThread(window, "./", window.getTitle(), "", false); + sleep(); + + textGLListener.setHeadBox(2, false); + textGLListener.setSampleCount(0); + window.display(); + textGLListener.printScreenOnGLThread(window, "./", window.getTitle(), "", false); + sleep(); + } }; + + if(textGLListener.setFontSet(FontFactory.UBUNTU, FontSet.FAMILY_LIGHT, FontSet.STYLE_NONE)) { + action_per_font.run(); + } - textGLListener.setTech(-400, -20, 0, -80, 0); - window.display(); - sleep(); + if(textGLListener.setFontSet(FontFactory.UBUNTU, FontSet.FAMILY_REGULAR, FontSet.STYLE_NONE)) { + action_per_font.run(); } if(textGLListener.setFontSet(FontFactory.JAVA, 0, 0)) { - textGLListener.setTech(-400, -30, 0f, -1000, 0); - window.display(); - window.display(); - sleep(); - - textGLListener.setTech(-400, -30, 0, -380, 0); - window.display(); - sleep(); - - textGLListener.setTech(-400, -20, 0, -80, 0); - window.display(); - sleep(); + action_per_font.run(); } destroyWindow(window); } private static class TextGLListener extends GPUTextRendererListenerBase01 { - String winTitle; - public TextGLListener(final RenderState rs, final int type, final int sampleCount, final boolean debug, final boolean trace) { super(rs, type, sampleCount, true, debug, trace); } @@ -219,10 +245,10 @@ public class TestTextRendererNEWT01 extends UITestCase { @Override public void attachInputListenerTo(final GLWindow window) { super.attachInputListenerTo(window); - winTitle = window.getTitle(); } - public void setTech(final float xt, final float yt, final float angle, final int zoom, final int sampleCount){ - setMatrix(xt, yt, zoom, angle, sampleCount); + public void setSampleCount(final int sampleCount){ + // setMatrix(xt, yt, zoom, angle, sampleCount); + setMatrix(0, 0, 0, 0f, sampleCount); } @Override @@ -240,14 +266,6 @@ public class TestTextRendererNEWT01 extends UITestCase { @Override public void display(final GLAutoDrawable drawable) { super.display(drawable); - - try { - printScreen(drawable, "./", winTitle, false); - } catch (final GLException e) { - e.printStackTrace(); - } catch (final IOException e) { - e.printStackTrace(); - } } } } diff --git a/src/test/com/jogamp/opengl/test/junit/graph/TestTextRendererNEWTBugXXXX.java b/src/test/com/jogamp/opengl/test/junit/graph/TestTextRendererNEWTBugXXXX.java index 7d285fe43..2c7967dd1 100644 --- a/src/test/com/jogamp/opengl/test/junit/graph/TestTextRendererNEWTBugXXXX.java +++ b/src/test/com/jogamp/opengl/test/junit/graph/TestTextRendererNEWTBugXXXX.java @@ -159,7 +159,7 @@ public class TestTextRendererNEWTBugXXXX extends UITestCase { gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); for(int i=0; i<fonts.length; i++) { final Font font = fonts[i]; - renderString(drawable, gl, renderer, font, textRenderUtil, font.getFullFamilyName(null).toString()+": "+issues, 0, 0==i?0:-1, -1000, sampleCountIO); + renderString(drawable, gl, renderer, font, textRenderUtil, font.getFullFamilyName()+": "+issues, 0, 0==i?0:-1, -1000, sampleCountIO); if(!onlyIssues) { renderString(drawable, gl, renderer, font, textRenderUtil, "012345678901234567890123456789", 0, -1, -1000, sampleCountIO); renderString(drawable, gl, renderer, font, textRenderUtil, "abcdefghijklmnopqrstuvwxyz", 0, -1, -1000, sampleCountIO); diff --git a/src/test/com/jogamp/opengl/test/junit/graph/demos/GPURendererListenerBase01.java b/src/test/com/jogamp/opengl/test/junit/graph/demos/GPURendererListenerBase01.java index 311abbcc3..b6b311ac9 100644 --- a/src/test/com/jogamp/opengl/test/junit/graph/demos/GPURendererListenerBase01.java +++ b/src/test/com/jogamp/opengl/test/junit/graph/demos/GPURendererListenerBase01.java @@ -126,8 +126,9 @@ public abstract class GPURendererListenerBase01 implements GLEventListener { final Object upObj = drawable.getUpstreamWidget(); if( upObj instanceof Window ) { final Window window = (Window) upObj; - final float[] sDPI = FontScale.perMMToPerInch( window.getPixelsPerMM(new float[2]) ); - System.err.println("DPI "+sDPI[0]+" x "+sDPI[1]); + final float[] sPpMM = window.getPixelsPerMM(new float[2]); + final float[] sDPI = FontScale.perMMToPerInch( new float[] { sPpMM[0], sPpMM[1] } ); + System.err.println("DPI "+sDPI[0]+" x "+sDPI[1]+", "+sPpMM[0]+" x "+sPpMM[1]+" pixel/mm"); final float[] hasSurfacePixelScale1 = window.getCurrentSurfaceScale(new float[2]); System.err.println("HiDPI PixelScale: "+hasSurfacePixelScale1[0]+"x"+hasSurfacePixelScale1[1]+" (has)"); @@ -245,15 +246,29 @@ public abstract class GPURendererListenerBase01 implements GLEventListener { public void printScreen(final GLAutoDrawable drawable, final String dir, final String tech, final String objName, final boolean exportAlpha) throws GLException, IOException { final StringWriter sw = new StringWriter(); final PrintWriter pw = new PrintWriter(sw); - pw.printf("-%03dx%03d-Z%04d-S%02d-%s", drawable.getSurfaceWidth(), drawable.getSurfaceHeight(), (int)Math.abs(zTran), sampleCount[0], objName); - + pw.printf("-%s-S%02d-Z%04d-snap%02d-%03dx%03d", objName, sampleCount[0], (int)Math.abs(zTran), screenshot_num++, drawable.getSurfaceWidth(), drawable.getSurfaceHeight()); final String filename = dir + tech + sw +".png"; if(screenshot.readPixels(drawable.getGL(), false)) { screenshot.write(new File(filename)); } } - - int screenshot_num = 0; + private int screenshot_num = 0; + + public void printScreenOnGLThread(final GLAutoDrawable drawable, final String dir, final String tech, final String objName, final boolean exportAlpha) { + drawable.invoke(false, new GLRunnable() { + @Override + public boolean run(final GLAutoDrawable drawable) { + try { + printScreen(drawable, dir, tech, objName, exportAlpha); + } catch (final GLException e) { + e.printStackTrace(); + } catch (final IOException e) { + e.printStackTrace(); + } + return true; + } + }); + } public void setIgnoreInput(final boolean v) { ignoreInput = v; @@ -337,25 +352,11 @@ public abstract class GPURendererListenerBase01 implements GLEventListener { } } else if(arg0.getKeyCode() == KeyEvent.VK_S){ - rotate(-1); - if(null != autoDrawable) { - autoDrawable.invoke(false, new GLRunnable() { - @Override - public boolean run(final GLAutoDrawable drawable) { - try { - final String modeS = Region.getRenderModeString(renderModes); - final String type = modeS + ( Region.hasVariableWeight(renderModes) ? "-vc" : "-uc" ) ; - printScreen(drawable, "./", "demo-"+type, "snap"+screenshot_num, false); - screenshot_num++; - } catch (final GLException e) { - e.printStackTrace(); - } catch (final IOException e) { - e.printStackTrace(); - } - return true; - } - }); - } + if(null != autoDrawable) { + final String modeS = Region.getRenderModeString(renderModes); + final String type = modeS + ( Region.hasVariableWeight(renderModes) ? "-vc" : "-uc" ) ; + printScreenOnGLThread(autoDrawable, "./", "demo-"+type, "", false); + } } } @Override diff --git a/src/test/com/jogamp/opengl/test/junit/graph/demos/GPUTextNewtDemo.java b/src/test/com/jogamp/opengl/test/junit/graph/demos/GPUTextNewtDemo.java index c3b1d1473..401450fdb 100644 --- a/src/test/com/jogamp/opengl/test/junit/graph/demos/GPUTextNewtDemo.java +++ b/src/test/com/jogamp/opengl/test/junit/graph/demos/GPUTextNewtDemo.java @@ -139,11 +139,11 @@ public class GPUTextNewtDemo { final float[] sDPI = FontScale.perMMToPerInch( window.getPixelsPerMM(new float[2]) ); final float font_ptpi = 12f; final float font_ppi = FontScale.toPixels(font_ptpi, sDPI[1]); - final AABBox fontNameBox = font.getMetricBounds(GPUTextRendererListenerBase01.textX2, font_ppi); + final AABBox fontNameBox = font.getMetricBounds(GPUTextRendererListenerBase01.textX1, font_ppi); System.err.println("GPU Text Newt Demo: "+font.fullString()); System.err.println("GPU Text Newt Demo: screen-dpi: "+sDPI[0]+"x"+sDPI[1]+", font "+font_ptpi+" pt, "+font_ppi+" pixel"); System.err.println("GPU Text Newt Demo: textX2: "+fontNameBox+" pixel"); - window.setSurfaceSize((int)(fontNameBox.getWidth()*1.1f), (int)(fontNameBox.getHeight()*2f)); + // window.setSurfaceSize((int)(fontNameBox.getWidth()*1.1f), (int)(fontNameBox.getHeight()*2f)); } // FPSAnimator animator = new FPSAnimator(60); diff --git a/src/test/com/jogamp/opengl/test/junit/graph/demos/GPUTextRendererListenerBase01.java b/src/test/com/jogamp/opengl/test/junit/graph/demos/GPUTextRendererListenerBase01.java index e0097bd74..5ae940da7 100644 --- a/src/test/com/jogamp/opengl/test/junit/graph/demos/GPUTextRendererListenerBase01.java +++ b/src/test/com/jogamp/opengl/test/junit/graph/demos/GPUTextRendererListenerBase01.java @@ -34,8 +34,9 @@ import com.jogamp.opengl.GL2ES2; import com.jogamp.opengl.GLAnimatorControl; import com.jogamp.opengl.GLAutoDrawable; import com.jogamp.opengl.GLException; +import com.jogamp.opengl.GLRunnable; import com.jogamp.opengl.fixedfunc.GLMatrixFunc; - +import com.jogamp.common.util.InterruptSource; import com.jogamp.graph.curve.Region; import com.jogamp.graph.curve.opengl.GLRegion; import com.jogamp.graph.curve.opengl.RegionRenderer; @@ -75,23 +76,23 @@ public abstract class GPUTextRendererListenerBase01 extends GPURendererListenerB int fontSet = FontFactory.UBUNTU; Font font; - int headType = 0; + int headType = 1; boolean drawFPS = true; final float fontSizeFName = 10f; final float fontSizeFPS = 10f; final int[] sampleCountFPS = new int[] { 8 }; float fontSizeHead = 12f; - float fontSizeBottom = 16f; - float dpiH = 96; + float fontSizeCenter = 16f; + float dpiV = 96; + float ppmmV = 1; final int fontSizeModulo = 100; String fontName; AABBox fontNameBox; String headtext; AABBox headbox; - static final String text1 = "abcdefghijklmnopqrstuvwxyz\nABCDEFGHIJKLMNOPQRSTUVWXYZ\n0123456789.:,;(*!?/\\\")$%^&-+@~#<>{}[]"; static final String text2 = "The quick brown fox jumps over the lazy dog"; - public static final String textX = + public static final String text_help = "JOGAMP graph demo using Resolution Independent NURBS\n"+ "JOGAMP JOGL - OpenGL ES2 profile\n"+ "Press 1/2 to zoom in/out the below text\n"+ @@ -103,7 +104,7 @@ public abstract class GPUTextRendererListenerBase01 extends GPURendererListenerB "Press i for live input text input (CR ends it, backspace supported)\n"+ "Press f to toggle fps. H for different text, space for font type\n"; - public static final String textX2 = + public static final String textX1 = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec nec sapien tellus. \n"+ "Ut purus odio, rhoncus sit amet commodo eget, ullamcorper vel urna. Mauris ultricies \n"+ "quam iaculis urna cursus ornare. Nullam ut felis a ante ultrices ultricies nec a elit. \n"+ @@ -113,21 +114,21 @@ public abstract class GPUTextRendererListenerBase01 extends GPURendererListenerB "in lorem. Maecenas in ipsum ac justo scelerisque sollicitudin. Quisque sit amet neque lorem, \n" + "-------Press H to change text---------"; - public static final String textX3 = - "I “Ask Jeff” or ‘Ask Jeff’. Take the chef d’œuvre! Two of [of] (of) ‘of’ “of” of? of! of*.\n"+ - "Les Woëvres, the Fôret de Wœvres, the Voire and Vauvise. Yves is in heaven; D’Amboise is in jail.\n"+ - "Lyford’s in Texas & L’Anse-aux-Griffons in Québec; the Łyna in Poland. Yriarte, Yciar and Ysaÿe are at Yale.\n"+ - "Kyoto and Ryotsu are both in Japan, Kwikpak on the Yukon delta, Kvæven in Norway, Kyulu in Kenya, not in Rwanda.…\n"+ - "Miłosz and Wū Wŭ all in the library? 1510–1620, 11:00 pm, and the 1980s are over.\n"+ - "Ut purus odio, rhoncus sit amet commodo eget, ullamcorper vel urna. Mauris ultricies \n"+ + public static final String textX2 = // Kvæven -> Kvaven (error) + "I “Ask Jeff” or ‘Ask Jeff’. Take the chef d’œuvre! Two of [of] (of) ‘of’ “of” of? of! of*. X\n"+ + "Les Woëvres, the Fôret de Wœvres, the Voire and Vauvise. Yves is in heaven; D’Amboise is in jail. X\n"+ + "Lyford’s in Texas & L’Anse-aux-Griffons in Québec; the Łyna in Poland. Yriarte, Yciar and Ysaÿe are at Yale. X\n"+ + "Kyoto and Ryotsu are both in Japan, Kwikpak on the Yukon delta, Kvaven in Norway, Kyulu in Kenya, not in Rwanda.… X\n"+ + "Von-Vincke-Straße in Münster, Vdovino in Russia, Ytterbium in the periodic table. Are Toussaint L’Ouverture, Wölfflin, Wolfe, X\n"+ + "Miłosz and Wū Wŭ all in the library? 1510–1620, 11:00 pm, and the 1980s are over. X\n"+ "-------Press H to change text---------"; - public static final String textX30 = + public static final String textX20 = // Kvæven -> Kvaven (error) "I “Ask Jeff” or ‘Ask Jeff’. Take the chef d’œuvre! Two of [of] (of) ‘of’ “of” of? of! of*.\n"+ "Two of [of] (of) ‘of’ “of” of? of! of*. Ydes, Yffignac and Ygrande are in France: so are Ypres,\n"+ "Les Woëvres, the Fôret de Wœvres, the Voire and Vauvise. Yves is in heaven; D’Amboise is in jail.\n"+ "Lyford’s in Texas & L’Anse-aux-Griffons in Québec; the Łyna in Poland. Yriarte, Yciar and Ysaÿe are at Yale.\n"+ - "Kyoto and Ryotsu are both in Japan, Kwikpak on the Yukon delta, Kvæven in Norway, Kyulu in Kenya, not in Rwanda.…\n"+ + "Kyoto and Ryotsu are both in Japan, Kwikpak on the Yukon delta, Kvaven in Norway, Kyulu in Kenya, not in Rwanda.…\n"+ "Walton’s in West Virginia, but «Wren» is in Oregon. Tlálpan is near Xochimilco in México.\n"+ "The Zygos & Xylophagou are in Cyprus, Zwettl in Austria, Fænø in Denmark, the Vøringsfossen and Værøy in Norway.\n"+ "Tchula is in Mississippi, the Tittabawassee in Michigan. Twodot is here in Montana, Ywamun in Burma.\n"+ @@ -138,7 +139,10 @@ public abstract class GPUTextRendererListenerBase01 extends GPURendererListenerB "Ut purus odio, rhoncus sit amet commodo eget, ullamcorper vel urna. Mauris ultricies \n"+ "-------Press H to change text---------"; - StringBuilder userString = new StringBuilder(textX2); + static final String textXLast = "abcdefghijklmnopqrstuvwxyz\nABCDEFGHIJKLMNOPQRSTUVWXYZ\n0123456789.:,;(*!?/\\\")$%^&-+@~#<>{}[]"; + + Window upstream_window = null; + StringBuilder userString = new StringBuilder(textX1); boolean userInput = false; public GPUTextRendererListenerBase01(final RenderState rs, final int renderModes, final int sampleCount, final boolean blending, final boolean debug, final boolean trace) { // NOTE_ALPHA_BLENDING: We use alpha-blending @@ -153,7 +157,6 @@ public abstract class GPUTextRendererListenerBase01 extends GPURendererListenerB try { // this.font = FontFactory.get(fontSet).getDefault(); this.font = FontFactory.get(fontSet).get(FontSet.FAMILY_LIGHT, FontSet.STYLE_NONE); - dumpFontNames(); this.fontName = font.toString(); } catch (final IOException ioe) { @@ -163,34 +166,53 @@ public abstract class GPUTextRendererListenerBase01 extends GPURendererListenerB setMatrix(0, 0, 0, 0f, sampleCount); } - void dumpFontNames() { - System.err.println("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); - System.err.println(font.getAllNames(null, "\n")); - System.err.println("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); - } - void switchHeadBox() { - headType = ( headType + 1 ) % 5 ; + setHeadBox( ( headType + 1 ) % 5, true ); + } + public int getHeadBoxType() { return headType; } + public AABBox getHeadBox() { return headbox; } + public void setHeadBox(final int choice, final boolean resize) { + headType = choice % 5 ; switch(headType) { case 0: headtext = null; break; case 1: - headtext= textX2; + headtext= textX1; break; case 2: - headtext= textX; + headtext= textX2; break; case 3: - headtext= textX3; + headtext= text_help; break; default: - headtext = text1; + headtext = textXLast; } - if(null != headtext) { - headbox = font.getMetricBounds(headtext, FontScale.toPixels(fontSizeHead, dpiH)); + if(resize && null != headtext) { + headbox = font.getMetricBounds(headtext, FontScale.toPixels(fontSizeHead, dpiV)); + if( headtext != text_help ) { + upsizeWindowSurface(upstream_window, true, (int)(headbox.getWidth()*1.1f), (int)(headbox.getHeight()*2f)); + } + } + } + + public static void upsizeWindowSurface(final Window window, final boolean off_thread, final int w, final int h) { + if( null == window ) { + return; + } + final int w2 = Math.max(window.getSurfaceWidth(), w); + final int h2 = Math.max(window.getSurfaceHeight(), h); + if( off_thread ) { + new InterruptSource.Thread() { + @Override + public void run() { + window.setSurfaceSize(w2, h2); + } }.start(); + } else { + window.setSurfaceSize(w2, h2); } } @@ -199,21 +221,27 @@ public abstract class GPUTextRendererListenerBase01 extends GPURendererListenerB super.init(drawable); final Object upObj = drawable.getUpstreamWidget(); if( upObj instanceof Window ) { - final Window window = (Window) upObj; - final float[] sDPI = FontScale.perMMToPerInch( window.getPixelsPerMM(new float[2]) ); - dpiH = sDPI[1]; - System.err.println("Using screen DPI of "+dpiH); + upstream_window = (Window) upObj; + final float[] sPpMM = upstream_window.getPixelsPerMM(new float[2]); + final float[] sDPI = FontScale.perMMToPerInch( new float[] { sPpMM[0], sPpMM[1] } ); + dpiV = sDPI[1]; + ppmmV = sPpMM[1]; + System.err.println("Using vertical screen DPI of "+dpiV+", "+ppmmV+" pixel/mm"); } else { - System.err.println("Using default DPI of "+dpiH); + System.err.println("Using vertical default DPI of "+dpiV+", "+ppmmV+" pixel/mm"); } - fontNameBox = font.getMetricBounds(fontName, FontScale.toPixels(fontSizeFName, dpiH)); - switchHeadBox(); + fontNameBox = font.getMetricBounds(fontName, FontScale.toPixels(fontSizeFName, dpiV)); + setHeadBox(headType, true); } @Override public void reshape(final GLAutoDrawable drawable, final int xstart, final int ystart, final int width, final int height) { super.reshape(drawable, xstart, ystart, width, height); + final Object upObj = drawable.getUpstreamWidget(); + if( upObj instanceof Window ) { + upstream_window = (Window) upObj; + } final float dist = 100f; nearPlaneX0 = nearPlane1Box.getMinX() * dist; nearPlaneY0 = nearPlane1Box.getMinY() * dist; @@ -229,6 +257,7 @@ public abstract class GPUTextRendererListenerBase01 extends GPURendererListenerB @Override public void dispose(final GLAutoDrawable drawable) { + upstream_window = null; regionFPS.destroy(drawable.getGL().getGL2ES2()); regionHead.destroy(drawable.getGL().getGL2ES2()); regionBottom.destroy(drawable.getGL().getGL2ES2()); @@ -237,6 +266,10 @@ public abstract class GPUTextRendererListenerBase01 extends GPURendererListenerB @Override public void display(final GLAutoDrawable drawable) { + final Object upObj = drawable.getUpstreamWidget(); + if( upObj instanceof Window ) { + upstream_window = (Window) upObj; + } final int width = drawable.getSurfaceWidth(); final int height = drawable.getSurfaceHeight(); final GL2ES2 gl = drawable.getGL().getGL2ES2(); @@ -256,14 +289,16 @@ public abstract class GPUTextRendererListenerBase01 extends GPURendererListenerB pmv.glMatrixMode(GLMatrixFunc.GL_MODELVIEW); pmv.glLoadIdentity(); rs.setColorStatic(0.1f, 0.1f, 0.1f, 1.0f); - final float pixelSizeFName = FontScale.toPixels(fontSizeFName, dpiH); - final float pixelSizeHead = FontScale.toPixels(fontSizeHead, dpiH); - final float pixelSizeBottom = FontScale.toPixels(fontSizeBottom, dpiH); + final float pixelSizeFName = FontScale.toPixels(fontSizeFName, dpiV); + final float pixelSizeHead = FontScale.toPixels(fontSizeHead, dpiV); + final float mmSizeHead = pixelSizeHead / ppmmV; + final float pixelSizeCenter = FontScale.toPixels(fontSizeCenter, dpiV); + final float mmSizeCenter = pixelSizeCenter / ppmmV; renderer.enable(gl, true); if( drawFPS ) { - final float pixelSizeFPS = FontScale.toPixels(fontSizeFPS, dpiH); + final float pixelSizeFPS = FontScale.toPixels(fontSizeFPS, dpiV); final float lfps, tfps, td; final GLAnimatorControl animator = drawable.getAnimator(); if( null != animator ) { @@ -276,8 +311,11 @@ public abstract class GPUTextRendererListenerBase01 extends GPURendererListenerB td = 0f; } final String modeS = Region.getRenderModeString(regionFPS.getRenderModes()); - final String text = String.format("%03.1f/%03.1f fps, v-sync %d, fontSize [head %.1f, bottom %.1f], %s-samples [%d, this %d], td %4.1f, blend %b, alpha-bits %d", - lfps, tfps, gl.getSwapInterval(), fontSizeHead, fontSizeBottom, modeS, getSampleCount()[0], sampleCountFPS[0], td, + final String text = String.format("%03.1f/%03.1f fps, v-sync %d, dpiV %.2f %.2f px/mm, font[head %.1fpt %.2fpx %.2fmm, center %.1fpt %.2fpx %.2fmm], %s-samples[%d, this %d], blend %b, alpha %d", + lfps, tfps, gl.getSwapInterval(), dpiV, ppmmV, + fontSizeHead, pixelSizeHead, mmSizeHead, + fontSizeCenter, pixelSizeCenter, mmSizeCenter, + modeS, getSampleCount()[0], sampleCountFPS[0], renderer.getRenderState().isHintMaskSet(RenderState.BITHINT_BLENDING_ENABLED), drawable.getChosenGLCapabilities().getAlphaBits()); @@ -321,7 +359,7 @@ public abstract class GPUTextRendererListenerBase01 extends GPURendererListenerB textRegionUtil.drawString3D(gl, renderer, font, headtext, null, getSampleCount()); } - dy += -headbox.getHeight() - font.getLineHeight(pixelSizeBottom); + dy += -headbox.getHeight() - font.getLineHeight(pixelSizeCenter); pmv.glMatrixMode(GLMatrixFunc.GL_MODELVIEW); pmv.glLoadIdentity(); @@ -330,7 +368,7 @@ public abstract class GPUTextRendererListenerBase01 extends GPURendererListenerB pmv.glTranslatef(getXTran(), getYTran(), getZTran()); pmv.glRotatef(getAngle(), 0, 1, 0); { - final float sxy = ( nearPlaneS * pixelSizeBottom ) / font.getMetrics().getUnitsPerEM(); + final float sxy = ( nearPlaneS * pixelSizeCenter ) / font.getMetrics().getUnitsPerEM(); pmv.glScalef(sxy, sxy, 1.0f); } rs.setColorStatic(0.9f, 0.0f, 0.0f, 1.0f); @@ -361,14 +399,14 @@ public abstract class GPUTextRendererListenerBase01 extends GPURendererListenerB public float getFontSizeHead() { return fontSizeHead; } public void fontBottomIncr(final int v) { - fontSizeBottom = Math.abs((fontSizeBottom + v) % fontSizeModulo) ; + fontSizeCenter = Math.abs((fontSizeCenter + v) % fontSizeModulo) ; dumpMatrix(true); } public void fontHeadIncr(final int v) { fontSizeHead = Math.abs((fontSizeHead + v) % fontSizeModulo) ; if(null != headtext) { - headbox = font.getMetricBounds(headtext, FontScale.toPixels(fontSizeHead, dpiH)); + headbox = font.getMetricBounds(headtext, FontScale.toPixels(fontSizeHead, dpiV)); } } @@ -379,9 +417,8 @@ public abstract class GPUTextRendererListenerBase01 extends GPURendererListenerB if(null != _font) { fontSet = set; font = _font; - fontName = font.getFullFamilyName(null).toString(); - fontNameBox = font.getMetricBounds(fontName, FontScale.toPixels(fontSizeFName, dpiH)); - dumpFontNames(); + fontName = font.getFullFamilyName(); + fontNameBox = font.getMetricBounds(fontName, FontScale.toPixels(fontSizeFName, dpiV)); return true; } } catch (final IOException ex) { @@ -396,9 +433,8 @@ public abstract class GPUTextRendererListenerBase01 extends GPURendererListenerB if(null != _font) { fontSet = set; font = _font; - fontName = font.getFullFamilyName(null).toString(); - fontNameBox = font.getMetricBounds(fontName, FontScale.toPixels(fontSizeFName, dpiH)); - dumpFontNames(); + fontName = font.getFullFamilyName()+" (head "+fontSizeHead+"pt)"; + fontNameBox = font.getMetricBounds(fontName, FontScale.toPixels(fontSizeFName, dpiV)); return true; } } catch (final IOException ex) { @@ -410,9 +446,9 @@ public abstract class GPUTextRendererListenerBase01 extends GPURendererListenerB public boolean isUserInputMode() { return userInput; } void dumpMatrix(final boolean bbox) { - System.err.println("Matrix: " + getXTran() + "/" + getYTran() + " x"+getZTran() + " @"+getAngle() +" fontSize "+fontSizeBottom); + System.err.println("Matrix: " + getXTran() + "/" + getYTran() + " x"+getZTran() + " @"+getAngle() +" fontSize "+fontSizeCenter); if(bbox) { - System.err.println("bbox: "+font.getMetricBounds(text2, nearPlaneS * FontScale.toPixels(fontSizeBottom, dpiH))); + System.err.println("bbox: "+font.getMetricBounds(text2, nearPlaneS * FontScale.toPixels(fontSizeCenter, dpiV))); } } @@ -436,9 +472,10 @@ public abstract class GPUTextRendererListenerBase01 extends GPURendererListenerB window.removeKeyListener(keyAction); } - public void printScreen(final GLAutoDrawable drawable, final String dir, final String tech, final boolean exportAlpha) throws GLException, IOException { - final String fn = font.getFullFamilyName(null).toString(); - printScreen(drawable, dir, tech, fn.replace(' ', '_'), exportAlpha); + @Override + public void printScreen(final GLAutoDrawable drawable, final String dir, final String tech, final String objName, final boolean exportAlpha) throws GLException, IOException { + final String fn = font.getFullFamilyName().replace(' ', '_').replace('-', '_'); + super.printScreen(drawable, dir, tech+"-"+fn, "text"+getHeadBoxType()+"-"+objName, exportAlpha); } float fontHeadScale = 1f; diff --git a/src/test/com/jogamp/opengl/test/junit/graph/demos/ui/Label.java b/src/test/com/jogamp/opengl/test/junit/graph/demos/ui/Label.java index 7d046e687..f7e6e3de9 100644 --- a/src/test/com/jogamp/opengl/test/junit/graph/demos/ui/Label.java +++ b/src/test/com/jogamp/opengl/test/junit/graph/demos/ui/Label.java @@ -102,9 +102,13 @@ public class Label extends UIShape { @Override protected void addShapeToRegion(final GL2ES2 gl, final RegionRenderer renderer) { - TextRegionUtil.processString(shapeVisitor, null, font, pixelSize, text, tempT1, tempT2); + final AffineTransform t_sxy = new AffineTransform(); // FIXME ? + final float sxy = pixelSize / font.getMetrics().getUnitsPerEM(); + t_sxy.setToScale(sxy, sxy); + TextRegionUtil.processString(shapeVisitor, t_sxy, font, text, tempT1, tempT2); final float[] ctr = box.getCenter(); setRotationOrigin( ctr[0], ctr[1], ctr[2]); + // scale(sxy, sxy, 1f); } @Override diff --git a/src/test/com/jogamp/opengl/test/junit/graph/demos/ui/Label0.java b/src/test/com/jogamp/opengl/test/junit/graph/demos/ui/Label0.java index 7882c713d..6641ce8b4 100644 --- a/src/test/com/jogamp/opengl/test/junit/graph/demos/ui/Label0.java +++ b/src/test/com/jogamp/opengl/test/junit/graph/demos/ui/Label0.java @@ -90,7 +90,10 @@ public class Label0 { box.reset(); this.region = region; this.tLeft = tLeft; - TextRegionUtil.processString(shapeVisitor, null, font, pixelSize, text, tempT1, tempT2); + final AffineTransform t_sxy = new AffineTransform(); // FIXME ? + final float sxy = pixelSize / font.getMetrics().getUnitsPerEM(); + t_sxy.setToScale(sxy, sxy); + TextRegionUtil.processString(shapeVisitor, t_sxy, font, text, tempT1, tempT2); this.region = null; this.tLeft = null; return box; diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/av/MovieCube.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/av/MovieCube.java index 134503520..f4b0540fa 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/av/MovieCube.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/av/MovieCube.java @@ -203,8 +203,8 @@ public class MovieCube implements GLEventListener { pixelScale = 1.0f / ( pixelSize1 * 20f ); // underlineSize: 'underline' amount of pixel below 0/0 (Note: lineGap is negative) final Font.Metrics metrics = font.getMetrics(); - final float lineGap = metrics.getLineGap(pixelSize1); - final float descent = metrics.getDescent(pixelSize1); + final float lineGap = pixelSize1 * metrics.getScale( metrics.getLineGapFU() ); + final float descent = pixelSize1 * metrics.getScale( metrics.getDescentFU() ); underlineSize = descent - lineGap; System.err.println("XXX: dpiH "+dpiH+", fontSize "+fontSize1+", pixelSize "+pixelSize1+", pixelScale "+pixelScale+", fLG "+lineGap+", fDesc "+descent+", underlineSize "+underlineSize); } |