It now uses GLUTesselator from 2.2.1 LWJGL to improve speed :
final char glyphChar = text.charAt(i);
final Rectangle2D glyphBounds = gv.getGlyphOutline(i).getBounds2D();
final int indexChar = i;
GL11.glPushMatrix();
GL11.glTranslated(glyphBounds.getX(), glyphBounds.getY(), 0);
GLList gllist = new GLGlyph(glyphChar, font.getSize()) {
@Override
public Runnable getList() {
return new Runnable() {
public void run() {
Shape glyph = gv.getGlyphOutline(indexChar, -(float) glyphBounds.getX(), -(float) glyphBounds.getY());
PathIterator pi = glyph.getPathIterator(null);
GLUtessellator tess = GLUtessellatorImpl.gluNewTess();
GLUtessellatorCallbackAdapter tessCb = new GLUtessellatorCallbackAdapter() {
@Override
public void begin(int type) {
GL11.glBegin(type);
}
@Override
public void vertex(Object vertexData) {
float[] vert = (float[]) vertexData;
GL11.glVertex2f(vert[0], vert[1]);
}
public void combine(double[] coords, Object[] data, float[] weight, Object[] outData) {
for (int i = 0; i < outData.length; i++) {
float[] combined = new float[6];
combined[0] = (float) coords[0];
combined[1] = (float) coords[1];
/*combined[2] = (float) coords[2];
for (int j = 3; j < 6; j++) {
for(int d = 0; d < data.length; d++)
combined[j] = weight[d] * data[d][j];
}*/
outData[i] = combined;
}
}
@Override
public void end() {
GL11.glEnd();
}
};
tess.gluTessCallback(GLU.GLU_TESS_BEGIN, tessCb);
tess.gluTessCallback(GLU.GLU_TESS_VERTEX, tessCb);
tess.gluTessCallback(GLU.GLU_TESS_COMBINE, tessCb);
tess.gluTessCallback(GLU.GLU_TESS_END, tessCb);
Point2D.Float current = new Point2D.Float();
tess.gluTessBeginPolygon(null);
while (!pi.isDone()) {
float[] coords = new float[6];
int path = pi.currentSegment(coords);
switch (pi.getWindingRule()) {
case PathIterator.WIND_EVEN_ODD:
tess.gluTessProperty(GLU.GLU_TESS_WINDING_RULE, GLU.GLU_TESS_WINDING_ODD);
break;
case PathIterator.WIND_NON_ZERO:
tess.gluTessProperty(GLU.GLU_TESS_WINDING_RULE, GLU.GLU_TESS_WINDING_NONZERO);
break;
default:
if (JXAenvUtils._debug) {
System.err.println(JXAenvUtils._JXAEnvOutput("no winding rule", JXAenvUtils.APP_WARNING));
}
break;
}
switch (path) {
case PathIterator.SEG_MOVETO:
/*System.err.println("PaIt begin move"); */
/*GL11.glBegin(GL11.GL_LINE_LOOP);*/
tess.gluTessBeginContour();
/*GL11.glVertex2f(coords[0], coords[1]);*/
tess.gluTessVertex(new double[]{coords[0], coords[1], 0.}, 0, new float[]{coords[0], coords[1], 0f});
current.x = coords[0];
current.y = coords[1];
break;
case PathIterator.SEG_CLOSE:
/*System.err.println("PaIt close");*/
/*GL11.glEnd();*/
tess.gluTessEndContour();
break;
case PathIterator.SEG_LINETO:
/*System.err.println("PaIt line");*/
/*GL11.glVertex2f(coords[0], coords[1]);*/
tess.gluTessVertex(new double[]{coords[0], coords[1], 0.}, 0, new float[]{coords[0], coords[1], 0f});
current.x = coords[0];
current.y = coords[1];
break;
case PathIterator.SEG_CUBICTO:
/*System.err.println("PaIt cubic");*/
for (Point2D.Float p : GLGeom._computeBezierCurve(new Point2D.Float[]{current, new Point2D.Float(coords[0], coords[1]), new Point.Float(coords[2], coords[3]), new Point.Float(coords[4], coords[5])}, font.getSize())) {
/*GL11.glVertex2f(p.x, p.y);*/
tess.gluTessVertex(new double[]{p.x, p.y, 0.}, 0, new float[]{p.x, p.y, 0f});
}
current.x = coords[4];
current.y = coords[5];
break;
case PathIterator.SEG_QUADTO:
/*System.err.println("PaIt quad");*/
for (Point2D.Float p : GLGeom._computeBezierCurve(new Point2D.Float[]{current, new Point2D.Float(coords[0], coords[1]), new Point.Float(coords[2], coords[3])}, font.getSize())) {
/*GL11.glVertex2f(p.x, p.y);*/
tess.gluTessVertex(new double[]{p.x, p.y, 0.}, 0, new float[]{p.x, p.y, 0f});
}
current.x = coords[2];
current.y = coords[3];
break;
default:
break;
}
pi.next();
}
tess.gluTessEndPolygon();
tess.gluDeleteTess();
}
};
}
};