Okay, here’s the code =)
/*
* Copyright (c) 2004 Terje Wiesener <wiesener@samfundet.no>
*
* This code may be freely used and distributed as long as this notice is kept intact.
*
* THE CODE IS SUPPLIED AS-IS, WITH NO GUARANTEE WHATSOEVER.
*
*/
package com.agentus.diplom.util.xith3d;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.util.HashMap;
import com.xith3d.loaders.texture.TextureLoader;
import com.xith3d.scenegraph.Appearance;
import com.xith3d.scenegraph.Billboard;
import com.xith3d.scenegraph.GeometryArray;
import com.xith3d.scenegraph.Material;
import com.xith3d.scenegraph.Shape3D;
import com.xith3d.scenegraph.Texture;
import com.xith3d.scenegraph.Texture2D;
import com.xith3d.scenegraph.TransformGroup;
import com.xith3d.scenegraph.TransparencyAttributes;
/** Implementation of 2D text for Xith3d
*
* @author Terje Wiesener <wiesener@samfundet.no>
*
*/
public class Text2D extends TransformGroup {
private static final TextureLoader tl;
private static final Graphics2D g;
private static final Material mat;
private static final TransparencyAttributes ta;
private static final HashMap textures;
static{
tl = new TextureLoader();
g = (new BufferedImage(100, 100,
BufferedImage.TYPE_INT_ARGB)).createGraphics();
mat = new Material();
mat.setLightingEnable(false);
ta = new TransparencyAttributes(TransparencyAttributes.BLENDED, 0.0f);
textures = new HashMap();
}
public Text2D(String text) {
// this(text, new Font("SansSerif", Font.BOLD, 20));//default font
this(text, new Font("Dialog", Font.BOLD, 20));//default font
}
public Text2D(String text, Font font) {
super();
TextInstance ti = new TextInstance(text, font);
Texture2D stringTex = (Texture2D)textures.get(ti);
if (stringTex == null){//texture is not cached
Rectangle2D bounds = font.getStringBounds(text, g.getFontRenderContext());
int textWidth = (int) bounds.getWidth();
int textHeight = (int) bounds.getHeight();
int width = 64 * (int)(Math.ceil((float)textWidth / 64.0f));//make width a multiple of 64
int height = 128;
BufferedImage bi = new BufferedImage(width, 128,
BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = (Graphics2D) bi.createGraphics();
g2.setColor(Color.WHITE);
g2.setFont(font);
g2.drawString(text, (width - textWidth) / 2, textHeight + 1);//draw in the top middle
stringTex = (Texture2D) tl.constructTexture(bi, "RGBA",
false, Texture.BASE_LEVEL, Texture.BASE_LEVEL_LINEAR,
Texture.WRAP, false, TextureLoader.SCALE_DRAW_BEST);
textures.put(ti, stringTex);//cache texture for later use
}
Appearance app = new Appearance();
app.setMaterial(mat);
app.setTexture(stringTex);
app.setTransparencyAttributes(ta);
Billboard billboard = new Billboard(GeometryArray.COORDINATES
| GeometryArray.TEXTURE_COORDINATE_2,
1.5f * ((float)stringTex.getWidth() / (float) stringTex.getHeight()), 1.5f);
this.addChild(new Shape3D(billboard, app));
}
private class TextInstance {
public Font font;
public String text;
public TextInstance(String text, Font font){
this.text = text;
this.font = font;
}
public int hashCode ()
{
int result = 17;
result += text.hashCode();
result += font.hashCode();
return result;
}
public boolean equals ( Object other )
{
if ( other == null ){
return false;
}
else if ( other instanceof TextInstance){
TextInstance otherText = (TextInstance) other;
if (!otherText.text.equals(this.text)) return false;
if (!otherText.font.equals(this.font)) return false;
return true;
}
else return false;
}
}
}
You’ll probably notice that the default height of the text object is 1.5, this is because I use it to place labels over objects with a radius of 1.0 =)
Terje