Glyph3D from Java3D Font3D

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;
   }

}