How to draw/render text in LWJGL ?

Started by chriddle, February 29, 2004, 20:45:59

Previous topic - Next topic

chriddle

Hi there!

I already posted this in javagaming.org but maybe this forum is a better place to ask.

We are starting to develop a little game for linux & windows. we found using java and lwjgl the best option in order to get it going fast. first tests were very satisfying so thanx for the great LWJGL.

Unfortunatly i didnt find any drawString() method in LWJGL and neither any example of the nehe lessons 13 o 14 using LWJGL. does it mean that there is no possibility to draw or render text in LWJGL?

what would be the best option to have strings rendered using LWJGL?

Thanx in advance!

Chris

princec

If you want to draw strings you've got to code it yourself :) The quick and easy way to do this is whip up a 256x256 luminance alpha texture and divide it into a grid of 8x8. Paint characters in there using some drawing tool like PSP. Then you can just render strings by drawing textured quads, using the character value to look up the coordinates.

Then there are other, far more fiddly ways of doing things, but that should get you started. Someone in here might have a handy ready made font texture you can use.

Cas :)

chriddle

I was hoping there might be an easier way to do it ...   :cry:

maybe it could be an extension to LWJGL in the future.

Thanx for your help, Cas. I´ll try the way you discribed although I´ll use a BufferedImage and draw a string using the Graphics object.

Chris

princec

You can't use Graphics to draw on the LWJGL window. You can only draw with OpenGL. Really, it's not very hard to do at all - it's nearly as simple as using plain old Java. You only have to write the routine once!

Cas :)

darkprophet

perhaps you should consider jME?

Its very very easy to render font to the screen. Its also very optimised.

*shameless promotion*  :roll:

chriddle

actually i thought about using jME.  :)

alhough we were not sure if we could use jME for text rendering only!?
we would prefer to have the code pretty clean opengl and use another api just to draw the text.

is it possible to use jME for text drawing only?

chris

Optus

A nifty class I wrote, demonstrating everything princec was talking about.  Use it at your own risk :D

import org.lwjgl.opengl.GL;

import java.nio.ByteBuffer;
import java.util.Vector;

import Poot3D.Math.Blend;
import Poot3D.Math.Math3D;
import Poot3D.Math.Vertex2;
import Main.AppContext;

/**
 * Created by IntelliJ IDEA.
 * User: adamprice (BIGGEST MOTHER f*ckING PIMP EVER)
 * Date: Nov 13, 2003
 * Time: 11:09:39 AM
 * To change this template use Options | File Templates.
 */
public class TextManager {
    static int NUM_FONTS = 3;
    static float FONT_DIM = 16f;

    int[] font = new int[NUM_FONTS];
    int listBase;
    Vector messagePool = new Vector();
    public Blend mode = new Blend(1,3);
    public void init () {
        font[0] = AppContext.textureManager.registerTex("data/fonts/font2.png");
        font[1] = AppContext.textureManager.registerTex("data/fonts/font3.png");
        font[2] = AppContext.textureManager.registerTex("data/fonts/output.png");
        buildList();
    }
    private void buildList () {
        listBase = GL.glGenLists(8*16*NUM_FONTS);
        int cnt = 0;
        for (int i = 0; i < NUM_FONTS; i++) {
            for (int y = 0; y < 8; y++) {
                for (int x = 0; x < 16; x++, cnt++) {
                    GL.glNewList(listBase+cnt, GL.GL_COMPILE);
                        AppContext.textureManager.bind(font[i]);
                        GL.glBegin(GL.GL_QUADS);								// Use A Quad For Each Character
                            GL.glMultiTexCoord2fARB(GL.GL_TEXTURE0_ARB, x/16f,y/8f); GL.glVertex2f(0f, 0f);
                            GL.glMultiTexCoord2fARB(GL.GL_TEXTURE0_ARB, x/16f,(y+1)/8f); GL.glVertex2f(0f, FONT_DIM);
                            GL.glMultiTexCoord2fARB(GL.GL_TEXTURE0_ARB, (x+1)/16f,(y+1)/8f); GL.glVertex2f(FONT_DIM, FONT_DIM);
                            GL.glMultiTexCoord2fARB(GL.GL_TEXTURE0_ARB, (x+1)/16f,y/8f); GL.glVertex2f(FONT_DIM, 0f);
                        GL.glEnd();
                    GL.glTranslatef(FONT_DIM, 0f, 0f);
                    GL.glEndList();
                }
            }
        }
    }
    public void render (float fdelta) {
        mode.blendFunc();
        for (int i = 0; i < messagePool.size(); i++) {
            renderText((Text)messagePool.get(i));
        }
    }

    public void renderText (Text text) {
        if (text.display) {
            GL.glListBase(-31+(8*16*text.setId));
            GL.glColor4f(text.color[0], text.color[1], text.color[2], 1.0f);
 ByteBuffer scratch = ByteBuffer.allocateDirect(text.message.getBytes().length);           
            scratch.put(text.message.getBytes());
            scratch.rewind();
            GL.glTranslatef(text.x,text.y,0f);
            GL.glScalef(text.scale.X, text.scale.Y, 1.0f);
            GL.glCallLists(scratch);
            GL.glTranslatef(-text.message.length()*FONT_DIM, 0f, 0f);
            GL.glScalef(1/text.scale.X, 1/text.scale.Y, 1.0f);
            GL.glTranslatef(-text.x, -text.y, 0f);
        }
    }
    public int addText(String message, int setId, int x, int y, float xscale, float yscale, float r, float g, float b) {
        Text text = new Text ();
        text.message = message;
        text.setId = setId;
        text.x = x;
        text.y = y;
        text.scale.X = xscale;
        text.scale.Y = yscale;
        text.color[0] = r;
        text.color[1] = g;
        text.color[2] = b;
        messagePool.add(text);
        return messagePool.indexOf(text);
    }
    public void update(int textId, String message, int setId, int x, int y, float xscale, float yscale, float r, float g, float b) {
        Text text = (Text) messagePool.get(textId);
        text.message = message;
        text.setId = setId;
        text.x = x;
        text.y = y;
        text.scale.X = xscale;
        text.scale.Y = yscale;
        text.color[0] = r;
        text.color[1] = g;
        text.color[2] = b;
    }
    public void update(int textId, int setId) {
        Text text = (Text) messagePool.get(textId);
        text.setId = setId;
    }
    public void update(int textId, int x, int y, float xscale, float yscale) {
        Text text = (Text) messagePool.get(textId);
        text.x = x;
        text.y = y;
        text.scale.X = xscale;
        text.scale.Y = yscale;
    }
    public void update(int textId, float r, float g, float b) {
        Text text = (Text) messagePool.get(textId);
        text.color[0] = r;
        text.color[1] = g;
        text.color[2] = b;
    }
    public void update(int textId, String message) {
        Text text = (Text) messagePool.get(textId);
        text.message = message;
    }

    public void hideText (int i) {
        ((Text)messagePool.get(i)).display = false;
    }
    public void showText (int i) {
        ((Text)messagePool.get(i)).display = true;
    }
    class Text {
        boolean display = true;
        String message = new String();
        int setId;
        int x,y;
        Vertex2 scale = new Vertex2();
        float[] color = new float[3];
    }
}

Mojomonkey

No, I wouldn't recommend using jME just for text rendering. You'd be better off with your own single class if that's all you need from it. However, I still recommend taking a look at it if you find yourself need other features. :) Don't want to turn you away from it completely.
ever send a man to do a monkey's work.


baegsi

I found this Nehe Tutorial helpful: http://nehe.gamedev.net/data/lessons/lesson.asp?lesson=13. It is working without the use of any texture :)
(there's a lwjgl port available at the bottom of the page: http://nehe.gamedev.net/data/lessons/lwjgl/lesson13.jar)

garazdawi

There are libraries for C++ that uses OpenGL to do freetype font rendering. One such is FTGL. I do however not know if there is any port to such a library to LWJGL, it would be really usefull though as it allows for a much larger flexibility...
 put the 'laughter' back in 'slaughter'
The LWJGL Wiki Documenation