Posted by
dmclean on
Jul 03, 2021; 3:04pm
URL: https://forum.jogamp.org/New-to-working-with-TextRegionUtil-tp4041168p4041178.html
After lots of looking around, reading old posts and experimenting with code I've got something that (mostly) works. The main basis for my solution comes from:
awt Glyph vector interpretationPoints on a quadThere are limitations to my solution:
1. It's based on pre-release JOGL code
2. Some fonts will not draw properly without a few hacks (M and W are particularly bad in many fonts).
3. This is aimed mainly at ASCII characters. I'm sure it will work for many other characters in the latin set. I'm sure it will not work for many other languages as is (mainly to do with the hacks required for some characters).
4. Works with the GL2 object.
This example is based on Courier Bold, it's the first font I found that did not require extra hacks for any characters. I was also able to get Arial to work with a few tricks. I can't tell if the rendering issues are with my glyph interpretation or the OutlineShape class. I assume it's something I'm doing wrong.
Rendering speed appears reasonable, at least it meets my requirements. There are definitely ways to improve the implementation to make it much faster for huge amounts of text. The important points of the solution are how to interpret the font glyph iterator and specifically plotting the quadratic sections of the glyphs.
Here is the class for a single character. The full example class is attached. Expanding the example code to draw strings is just a matter of getting the glyph bounds from the GlyphVector and using the bounds to translate for each character.
static class CharacterDraw
{
float advance;
int glListID;
CharacterDraw(GL2 gl, java.awt.Font f, char c)
{
GlyphVector v = f.createGlyphVector(new FontRenderContext(null, true, false), Character.toString(c));
Shape glyph = v.getGlyphOutline(0);
PathIterator pi = glyph.getPathIterator(null);
OutlineShape shape = new OutlineShape(SVertex.factory());
double[] coords = new double[6];
double[] prev = new double[2];
advance = v.getGlyphMetrics(0).getAdvanceX();
while(!pi.isDone()) {
int lineType = pi.currentSegment(coords);
switch(lineType)
{
case PathIterator.SEG_CLOSE:
break;
case PathIterator.SEG_CUBICTO:
break;
case PathIterator.SEG_LINETO:
shape.addVertex((float) coords[0], (float) coords[1], true);
System.arraycopy(coords, 0, prev, 0, 2);
break;
case PathIterator.SEG_MOVETO:
shape.addEmptyOutline();
shape.addVertex((float) coords[0], (float) coords[1], true);
System.arraycopy(coords, 0, prev, 0, 2);
break;
case PathIterator.SEG_QUADTO:
updateQuad(shape, prev, coords);
System.arraycopy(coords, 2, prev, 0, 2);
break;
}
pi.next();
}
glListID = gl.glGenLists(1);
gl.glNewList(glListID, GL_COMPILE);
gl.glBegin(GL_TRIANGLES);
for (Triangle t : shape.getTriangles(OutlineShape.VerticesState.QUADRATIC_NURBS))
{
for (Vertex vert : t.getVertices())
gl.glVertex2f(vert.getX(), vert.getY());
}
gl.glEnd();
gl.glEndList();
}
void updateQuad(OutlineShape shape, double[] prev, double[] coords)
{
double xStart = prev[0], xEnd = coords[2], xCtrl = coords[0];
double yStart = prev[1], yEnd = coords[3], yCtrl = coords[1];
//Draws curs as 3 sections - which generally appears to be enough
//No need to draw the first point of the curve, it has already been added by now.
for (int n = 1; n < 3; ++n)
{
//
https://stackoverflow.com/questions/7920804/calculating-a-quad-curve-between-two-xy-points double f = n * (1/3.0);
double x = (((xEnd-xCtrl)*f+xCtrl)-((xCtrl-xStart)*f+xStart))*f+((xCtrl-xStart)*f+xStart);
double y = (((yEnd-yCtrl)*f+yCtrl)-((yCtrl-yStart)*f+yStart))*f+((yCtrl-yStart)*f+yStart);
shape.addVertex((float)x, (float)y, true);
}
shape.addVertex((float)coords[2], (float)coords[3], true);
}
void draw(GL2 gl)
{
gl.glCallList(glListID);
}
void destroy(GL2 gl)
{
gl.glDeleteLists(glListID, 1);
}
}
FontTest2.javacourbd.ttf