package gl; import gl.animations.AnimationFaceToCamera; import gl.scenegraph.MeshComponent; import gl.scenegraph.Shape; import java.util.HashMap; import javax.microedition.khronos.opengles.GL10; import util.Log; import util.Vec; import worldData.Visitor; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Typeface; import android.widget.TextView; /** * I rapidly changing text (like a distance in meters) should not be created * like in {@link GLFactory#newTextObject(String, Vec, Context, GLCamera)} * because a new texture would have to be generated each time. This class was * designed for such scenarios. It is slower to render for large numbers of * {@link GLText} objects (because of the {@link MeshComponent} overhead) but if * you have rapidly changing text you should use this class. * * @author Spobo * */ public class GLText extends MeshComponent { private static final float CHAR_DIST = 0.5f; private static final float CHAR_SIZE = 1f; private static final String LOG_TAG = "GLText"; private String myText; private boolean textLoaded; private Context myContext; private final HashMap<String, MeshComponent> myTextMap; private GLCamera myCamera; /** * @param text * The text that should be displayed. Can be changed with * {@link GLText#changeTextTo(String)} * @param context * @param textMap * hte already created characters will be stored in here, so pass * a new {@link HashMap} or maybe also a already initialized * {@link HashMap} if you want to use a custom font or something * similar * @param glCamera * to allow the text to face the camera */ public GLText(String text, Context context, HashMap<String, MeshComponent> textMap, GLCamera glCamera) { super(null); myText = text; myContext = context; myTextMap = textMap; myCamera = glCamera; } @Override public boolean accept(Visitor visitor) { return visitor.default_visit(this); } @Override public void draw(GL10 gl, Renderable parent) { if (!textLoaded) { loadText(myText); textLoaded = true; } } protected void loadText(String text) { int textLength = text.length(); for (int i = 0; i < textLength; i++) { MeshComponent m = loadCharMesh("" + text.charAt(i), i, textLength); this.addChild(m); } this.addAnimation(new AnimationFaceToCamera(myCamera)); } protected MeshComponent loadCharMesh(String s, int charNr, int textLenght) { MeshComponent value = loadFromMap(s); if (value == null) { value = createNewCharMesh(s); registerValueInMap(s, value); } else { Log.d(LOG_TAG, "Char allready loaded: " + s); } // to allow positioning wrap the result: float pos = charNr * -CHAR_DIST; pos -= textLenght / 2 * -CHAR_DIST; MeshComponent box = new Shape(null, new Vec(pos, 0, 0)); box.addChild(value); return box; } private void registerValueInMap(String key, MeshComponent value) { if (myTextMap != null) { myTextMap.put(key, value); } } private MeshComponent loadFromMap(String key) { if (myTextMap != null) { return myTextMap.get(key); } return null; } protected MeshComponent createNewCharMesh(String s) { MeshComponent mesh = GLFactory.getInstance().newTexturedSquare( "char" + s, generateText(s), CHAR_SIZE); return mesh; } protected Bitmap generateText(String s) { TextView v = new TextView(myContext); v.setTypeface(null, Typeface.BOLD); v.setText(s); return util.IO.loadBitmapFromView(v); } public void changeTextTo(String s) { myText = s; clearChildren(); textLoaded = false; } }