/** * @param c * @param font * @return GlyphVector using a default rendering context */ private SVGGlyph createGlyph(int c, Font font) { GlyphVector glyphVector = font.createGlyphVector( // flipping is done by SVGGlyph new FontRenderContext(null, true, true), // unicode to char String.valueOf((char) c)); // create and store the SVG Glyph return new SVGGlyph(glyphVector.getGlyphOutline(0), c, glyphVector.getGlyphMetrics(0)); }
/** * Returns the 3D bounding box of the specified glyph code. * * @param glyphCode the glyphCode from the original 2D Font * @param bounds the 3D glyph's bounds */ public void getBoundingBox(int glyphCode, BoundingBox bounds) { int[] gCodes = {glyphCode}; GlyphVector gVec = font.createGlyphVector(frc, gCodes); Rectangle2D.Float bounds2d = (Rectangle2D.Float) (((GlyphMetrics) (gVec.getGlyphMetrics(0))).getBounds2D()); Point3d lower = new Point3d(bounds2d.x, bounds2d.y, 0.0); Point3d upper; if (fontExtrusion != null) { upper = new Point3d( bounds2d.x + bounds2d.width, bounds2d.y + bounds2d.height, fontExtrusion.length); } else { upper = new Point3d(bounds2d.x + bounds2d.width, bounds2d.y + bounds2d.height, 0.0); } bounds.setLower(lower); bounds.setUpper(upper); }
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}; }
private void parseProblemGlyphs() { myCheckedForProblemGlyphs = true; BufferedImage buffer = UIUtil.createImage(20, 20, BufferedImage.TYPE_INT_RGB); final Graphics graphics = buffer.getGraphics(); if (!(graphics instanceof Graphics2D)) { return; } final FontRenderContext context = ((Graphics2D) graphics).getFontRenderContext(); char[] charBuffer = new char[1]; for (char c = 0; c < 128; c++) { if (!myFont.canDisplay(c)) { continue; } charBuffer[0] = c; final GlyphVector vector = myFont.createGlyphVector(context, charBuffer); final float y = vector.getGlyphMetrics(0).getAdvanceY(); if (Math.round(y) != 0) { mySymbolsToBreakDrawingIteration.add(c); } } myHasGlyphsToBreakDrawingIteration = !mySymbolsToBreakDrawingIteration.isEmpty(); }
private TessOutput tesselateString(String s) { GlyphVector gv = _font.createGlyphVector(_frc, s); Shape shape = gv.getOutline(); // AffineTransform at = new AffineTransform(); at.scale(1, -1); PathIterator pIt = shape.getPathIterator(at, _font.getSize() / 200.0); // Create a GLU tesselator GLUtessellator tess = GLU.gluNewTess(); CharTesselator tessAdapt = new CharTesselator(); GLU.gluTessCallback(tess, GLU.GLU_TESS_VERTEX, tessAdapt); GLU.gluTessCallback(tess, GLU.GLU_TESS_BEGIN, tessAdapt); GLU.gluTessCallback(tess, GLU.GLU_TESS_END, tessAdapt); GLU.gluTessCallback(tess, GLU.GLU_TESS_COMBINE, tessAdapt); GLU.gluTessCallback(tess, GLU.GLU_TESS_ERROR, tessAdapt); int winding = pIt.getWindingRule(); if (winding == PathIterator.WIND_EVEN_ODD) GLU.gluTessProperty(tess, GLU.GLU_TESS_WINDING_RULE, GLU.GLU_TESS_WINDING_ODD); else if (winding == PathIterator.WIND_NON_ZERO) GLU.gluTessProperty(tess, GLU.GLU_TESS_WINDING_RULE, GLU.GLU_TESS_WINDING_NONZERO); else assert (false); // PathIterator should only return these two winding rules GLU.gluBeginPolygon(tess); GLU.gluTessNormal(tess, 0, 0, 1); double[] first = null; double[] v; while (!pIt.isDone()) { v = new double[3]; int type = pIt.currentSegment(v); v[2] = 0.0; if (type == PathIterator.SEG_MOVETO) { first = v; GLU.gluNextContour(tess, GLU.GLU_UNKNOWN); GLU.gluTessVertex(tess, v, 0, v); } else if (type == PathIterator.SEG_LINETO) { GLU.gluTessVertex(tess, v, 0, v); } else if (type == PathIterator.SEG_CLOSE) { assert (first != null); // If this is true, there is an error in the AWT path iterator GLU.gluTessVertex(tess, first, 0, first); first = null; } else { assert (false); // The path itertor should not return other path types here } pIt.next(); } GLU.gluEndPolygon(tess); int numVerts = tessAdapt.getVerts().size(); double[] verts = new double[numVerts]; int count = 0; for (double d : tessAdapt.getVerts()) { verts[count++] = d; } TessOutput ret = new TessOutput(); ret.verts = verts; ret.bounds = gv.getVisualBounds(); ret.advances = new double[s.length()]; for (int i = 0; i < s.length(); ++i) { ret.advances[i] = gv.getGlyphMetrics(i).getAdvance(); } return ret; }