Revision: 4111 http://vexi.svn.sourceforge.net/vexi/?rev=4111&view=rev Author: clrg Date: 2011-04-19 13:04:32 +0000 (Tue, 19 Apr 2011)
Log Message: ----------- Fix #47 - tweak glyph rendering and add [commented out] alternative rendering logic Modified Paths: -------------- trunk/org.vexi-core.main/src/main/java/org/vexi/graphics/Font.java Modified: trunk/org.vexi-core.main/src/main/java/org/vexi/graphics/Font.java =================================================================== --- trunk/org.vexi-core.main/src/main/java/org/vexi/graphics/Font.java 2011-04-15 00:55:53 UTC (rev 4110) +++ trunk/org.vexi-core.main/src/main/java/org/vexi/graphics/Font.java 2011-04-19 13:04:32 UTC (rev 4111) @@ -47,6 +47,7 @@ public int width = -1; ///< the width of the glyph public int height = -1; ///< the height of the glyph public byte[] data = null; ///< the alpha channel samples for this font + public int widthadjust = 0; ///< no kerning; adjust width according to sub-pixel alphas void render() { if (!isLoaded) { try { font.renderGlyph(this); } @@ -116,20 +117,53 @@ glyphs[c] = g = Platform.createGlyph(this, c); } g.render(); - // avoid clipping first character - int ox = x + width; - if (i!=0 || g.bearingx>0) { - ox += g.bearingx; + + // useful glyph metrics for [visual] debugging + //System.out.println(c+" ("+((int)c)+") at "+this.pointsize+" ("+threshold+"): "+g.bearingx+", "+g.width+", "+g.advance+", -- "+width); + + // SOLUTION 1 - simple; use glyph metrics [almost] without modification + if (g.bearingx<0) { + // neutralise negative bearingx to prevent first + // character clipping and also glyph sandwiching + width += -g.bearingx; } + int ox = x + width + g.bearingx; + width += g.advance; + +// // SOLUTION 2 - alternative placement algorithm +// // use pre-analysis of glyphs to be a bit smarter +// // PROBLEM: perhaps a bit too close as text layout +// // although consistent, is a bit too congested +// int ox; +// int threshold = pointsize>>1; +// if (i==0 && g.bearingx<0) { +// // neutralise negative bearingx for the first character +// // to avoid clipping characters such as 'J' in vera +// width += -g.bearingx; +// } +// +// // REMARK: at lower point sizes, as we are doing per-glyph +// // rendering and not using freetype's inbuilt kerning, we +// // have to do a bit of hackery to make the glyphs look a bit +// // better when side-by-side, otherwise some smaller glyphs +// // will touch pixels with others and others leave big gaps +// ox = x + width; +// width += g.advance-g.bearingx; +// if (g.width+g.bearingx>=g.advance && g.width<threshold-1) +// width += g.bearingx>0 ? g.bearingx : 1; +// if (g.width==g.advance && g.advance>=threshold) +// width ++; + + // VISUAL DEBUGGING + //if (buf != null) { + // // places a marker by the drawing point of the glyph + // buf.fillTrapezoid(ox, ox+1, y + g.font.max_ascent, ox, ox+1, y + g.font.max_ascent + 1, 0xffffff00); + //} + // render glyph and move on if (buf != null) { buf.drawGlyph(g, ox, y + g.font.max_ascent - g.baseline, cx1, cy1, cx2, cy2, textcolor); } - width += g.advance; - // take into account clipping avoidance - if (i==0 && g.bearingx<0) { - width -= g.bearingx; - } } } @@ -147,11 +181,37 @@ } g.render(); height = java.lang.Math.max(height, max_ascent + max_descent); + + // SOLUTION 1 - simple; use glyph metrics [almost] without modification + if (g.bearingx<0) { + // neutralise negative bearingx to prevent first + // character clipping and also glyph sandwiching + width += -g.bearingx; + } width += g.advance; - // take into account clipping avoidance - if (i==0 && g.bearingx<0) { - width -= g.bearingx; - } + +// // SOLUTION 2 - alternative placement algorithm +// // use pre-analysis of glyphs to be a bit smarter +// // PROBLEM: perhaps a bit too close as text layout +// // although consistent, is a bit too congested +// int ox; +// int threshold = pointsize>>1; +// if (i==0 && g.bearingx<0) { +// // neutralise negative bearingx for the first character +// // to avoid clipping characters such as 'J' in vera +// width += -g.bearingx; +// } +// +// // REMARK: at lower point sizes, as we are doing per-glyph +// // rendering and not using freetype's inbuilt kerning, we +// // have to do a bit of hackery to make the glyphs look a bit +// // better when side-by-side, otherwise some smaller glyphs +// // will touch pixels with others and others leave big gaps +// width += g.advance-g.bearingx; +// if (g.width+g.bearingx>=g.advance && g.width<threshold-1) +// width += g.bearingx>0 ? g.bearingx : 1; +// if (g.width==g.advance && g.advance>=threshold) +// width ++; } return ((((long)width) << 32) | (height & 0xffffffffL)); } @@ -247,6 +307,12 @@ //long start = System.currentTimeMillis(); + /* + * Stage 1: + * Using FreeType, compiled as MIPS and executed by NestedVM, + * we render a given font glyph at the specified pointsize. + * This returns an alphamask as a byte array (byte & 0xff) + */ rt.call("render",glyph.c,glyph.font.pointsize.intValue()); rtCheck(); @@ -263,6 +329,51 @@ int addr = rt.getUserInfo(0); rt.copyin(addr, glyph.data, glyph.width * glyph.height); + /* + * Stage 2: (SOLUTION 2 ONLY) + * We render glyphs only once, contrary to the standard + * freetype text rendering, so subpixel spacing between + * characters is not implemented. We must do placement + * using only the given characteristics of each glyph, + * but since these characteristics - especially at low + * pointsizes - are rounded, they're inaccurate for our + * purposes and thus, without analysis, if attempting to + * place these rendered glyphs side-by-side, there will + * be inconsistencies with the distances spanned between + * some characters. + */ +// if (glyph.width+glyph.bearingx>=glyph.advance && pointsize>>1 > glyph.advance) { +// final int darkness_threshold = 56; +// boolean above_threshold = false; +// for (int i=0; glyph.height>i; i++) { +// // check the last column of the glyph to ensure +// // it meets the visible alpha threshold +// if ((glyph.data[i*glyph.width + (glyph.width-1)] & 0xff) > darkness_threshold) { +// above_threshold = true; +// break; +// } +// } +// if (above_threshold) { +// //System.out.println("advancing: "+glyph.c); +// glyph.advance ++; +// } +// } + +// // console visualisation of the glyph +// // i.e. output alphas (number) array +// if (glyph.c == 'o' || glyph.c == 'w') { +// System.out.println(glyph.c+" at "+pointsize+", advance:"+glyph.advance+", width:"+glyph.width+", bearingx:"+glyph.bearingx); +// for (int i=0; glyph.height>i; i++) { +// for (int j=0; glyph.width>j; j++) { +// int b = glyph.data[i*glyph.width + j] & 0xff; +// String out = ""+b; +// while (out.length()<4) out = " "+out; +// System.out.print(out+", "); +// } +// System.out.print('\n'); +// } +// } + glyph.isLoaded = true; } catch (Exception e) { // FEATURE: Better error reporting (throw an exception?) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. ------------------------------------------------------------------------------ Benefiting from Server Virtualization: Beyond Initial Workload Consolidation -- Increasing the use of server virtualization is a top priority.Virtualization can reduce costs, simplify management, and improve application availability and disaster protection. Learn more about boosting the value of server virtualization. http://p.sf.net/sfu/vmware-sfdev2dev _______________________________________________ Vexi-svn mailing list Vexi-svn@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/vexi-svn