Here's my little class that creates a TriMesh from a glyph using Java3D.
I've implemented it just because the JME's Text3D is not so accurate in tessellating/extruding glyphs.
The usage is straightforward:
float samples = 1f/100;
FontExtrusion fe = JMEGlyph3D.createFontExtrusion(1,.3f,samples);
JMEGlyph3D glyph = new JMEGlyph3D("Arial", Font.BOLD, 1, samples , fe);
TriMesh geom = glyph.getGlyph3D('W');
Have fun,
Mik
/*
* Created on 13/nov/07 by Mik Of ClassX
*/
import java.awt.Font;
import java.awt.Shape;
import java.awt.geom.GeneralPath;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import javax.media.j3d.Font3D;
import javax.media.j3d.FontExtrusion;
import javax.media.j3d.GeometryArray;
import com.jme.math.Vector2f;
import com.jme.scene.TriMesh;
import com.jme.util.geom.BufferUtils;
/**
* @author Michele
*/
public class JMEGlyph3D
{
private Font3D font3D = null;
/**
* @param fontname
* @param style
* @param size
* @param tolerance
* @param fe
*/
public JMEGlyph3D(String fontname, int style, int size, float tolerance, FontExtrusion fe)
{
font3D = new Font3D(new Font(fontname, style, size), tolerance, fe);
}
/**
* @param extrusionKind
* @param extrusionSize
* @param tolerance
* @return
*/
public static FontExtrusion createFontExtrusion(int extrusionKind, float extrusionSize, float tolerance)
{
return new FontExtrusion(createExtrusionPath(extrusionKind, extrusionSize), tolerance);
}
/**
* @param extType
* @param extrusionSize
* @return
*/
private static Shape createExtrusionPath(int extType, float extrusionSize)
{
Shape path = null;
GeneralPath gp = new GeneralPath();
float mx = .3f;
float my = .3f;
float extr = extrusionSize;
switch (extType)
{
case 0:
gp.moveTo(0, 0);
gp.lineTo(mx / 4, my / 4);
gp.lineTo(extr + mx / 4, my / 4);
gp.lineTo(extr + mx / 4 + mx / 4, 0);
path = gp;
break;
case 1:
gp.moveTo(0, 0);
gp.lineTo(mx / 4, my / 4);
gp.curveTo(mx / 4, my / 4, (extr + mx / 4) / 2, my, extr + mx / 4, my / 4);
gp.lineTo(extr + mx / 4 + mx / 4, 0);
path = gp;
break;
}
return path;
}
/**
* @param c
* @return
*/
public TriMesh getGlyph3D(char c)
{
// retrieve glyph geometry from java3d
GeometryArray m_GeometryArray = font3D.getGlyphGeometry(c);
// set properties for reading
m_GeometryArray.setCapability(GeometryArray.ALLOW_COORDINATE_READ);
m_GeometryArray.setCapability(GeometryArray.ALLOW_COUNT_READ);
m_GeometryArray.setCapability(GeometryArray.ALLOW_NORMAL_READ);
m_GeometryArray.setCapability(GeometryArray.ALLOW_COLOR_READ);
m_GeometryArray.setCapability(GeometryArray.ALLOW_FORMAT_READ);
m_GeometryArray.setCapability(GeometryArray.ALLOW_TEXCOORD_READ);
m_GeometryArray.setCapability(GeometryArray.ALLOW_VERTEX_ATTR_READ);
// compute vertex n.
int numVert = m_GeometryArray.getVertexCount();
// make a copy of the original coordinates
float[] coords = new float[3 * numVert];
m_GeometryArray.getCoordinates(0, coords);
FloatBuffer coords_fb = BufferUtils.createFloatBuffer(coords);
// make a copy of the original normals
float[] normals = new float[3 * numVert];
m_GeometryArray.getNormals(0, normals);
FloatBuffer normals_fb = BufferUtils.createFloatBuffer(normals);
// create vertex indexes
int[] indicies = new int[numVert];
for (int i = 0; i < indicies.length; i++)
{
indicies[i] = i;
}
IntBuffer indicies_ib = BufferUtils.createIntBuffer(indicies);
// create texture coords
Vector2f[] texcoords = new Vector2f[numVert];
float min_x = coords[0];
float max_x = min_x;
float min_y = coords[1];
float max_y = min_y;
// go through the vertices
for (int i = 0; i < numVert; i++)
{
int id = i * 3;
if (coords[id] < min_x)
{
min_x = coords[id];
}
if (coords[id] > max_x)
{
max_x = coords[id];
}
if (coords[id + 1] < min_y)
{
min_y = coords[i + 1];
}
if (coords[id + 1] > max_y)
{
max_y = coords[id + 1];
}
}
final float width = max_x - min_x;
final float height = max_y - min_y;
final float u_per_x = 1.0f / width;
final float v_per_y = 1.0f / height;
final float min_u_per_x = min_x * u_per_x;
final float min_v_per_y = min_y * v_per_y;
// compute texture coords
for (int i = 0; i < numVert; i++)
{
int id = i * 3;
Vector2f v = new Vector2f(coords[id] - min_u_per_x, coords[id + 1] - min_v_per_y);
texcoords[i] = v;
}
// create texture coords (QUICK)
/*
* for(int i = 0; i < m_GeometryArray.getVertexCount(); i++) { Vector2f v = new Vector2f(coords[i*3],
* coords[i*3+1]); texcoords[i] = v; }
*/
FloatBuffer texture = BufferUtils.createFloatBuffer(texcoords);
TriMesh geom = new TriMesh("glyph " + c, coords_fb, normals_fb, null, texture, indicies_ib);
return geom;
}
}