2D fonts using Ortho - text doesn't display

Started by chisser98, March 13, 2008, 19:11:07

Previous topic - Next topic

chisser98

Hey all!

I'm sure most of you hate getting 2D questions, but I've done searching for this topic, followed tutorials, etc, and I can't seem to get it to work! I'm using the LWJGL conversion of NeHe's tutorial #17 on Bitmap Fonts, but no dice.  The 2D fonts just do not want to display on the screen!

Here's the code for my BitmapFont class (it controls loading of the font and printing it):
package common.gui.font;

import common.gui.texture.*;

import java.awt.Color;
import java.awt.Font;
import java.awt.image.BufferedImage;
import java.awt.Graphics2D;
import java.awt.FontMetrics;

import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import java.nio.ByteOrder;

import org.lwjgl.opengl.GL11;

public class BitmapFont {

	private static final BitmapFont source = new BitmapFont();
	
	private static final Color OPAQUE_WHITE = new Color(0xFFFFFFFF, true);
	private static final Color TRANSPARENT_BLACK = new Color(0x00000000, true);
	
	/** The display list id, where each character to print to the screen
	 *  is added to this value.  For example, listBase+65 would be the character
	 *  'A'.*/
	private int listBase;
	/** The texture for this font */
	private Texture texture;
	/** The current font */
	private String currentFont = "Courier New";
	
	
	private BitmapFont() {
		init();
	}
	
	private void init() {
		buildFont();
		buildDisplayLists();
	}
	
	private void buildFont() {
		try {
			texture = TextureMgr.get().getTexture("res/Font.bmp");
		} catch (Exception e) {
			e.printStackTrace();
			System.exit(0);
		}
	}
	
	private int testid;
	/**
	 * Create the display lists used for drawing characters to the screen.
	 */
	private void buildDisplayLists() {
		listBase = GL11.glGenLists(256); // Storage For 256 Characters
		testid = GL11.glGenLists(1);
		
		
		float x = (float)(texture.getWidth()/2);
		float y = (float)(texture.getHeight()/2);
		x = 2.0f;
		y = 2.0f;
		GL11.glNewList(testid, GL11.GL_COMPILE);
		texture.bind();
		GL11.glBegin(GL11.GL_QUADS);
			GL11.glTexCoord2f(1.0f, 0.0f);
			GL11.glVertex3f(x, -y, 0.0f);
			GL11.glTexCoord2f(1.0f, 1.0f);
			GL11.glVertex3f(x, y, 0.0f);
			GL11.glTexCoord2f(0.0f, 1.0f);
			GL11.glVertex3f(-x, y, 0.0f);
			GL11.glTexCoord2f(0.0f, 0.0f);
			GL11.glVertex3f(-x, -y, 0.0f);
		GL11.glEnd();
		GL11.glEndList();

        /* Generate the display lists.  One for each character in the standard/extended ASCII chart.
         */
        float textureDelta = 1.0f / 16.0f;
        for(int i=0;i<256;i++) {
            float u = ((float)(i % 16)) / 16.0f;
            float v = 1.f - (((float)(i / 16)) / 16.0f);
            GL11.glNewList(listBase + i, GL11.GL_COMPILE);
            texture.bind();
            GL11.glBegin(GL11.GL_QUADS);
                GL11.glTexCoord2f(u, v - textureDelta);
                GL11.glVertex3f(-0.0450f, -0.0450f, 0.0f);
                GL11.glTexCoord2f((u + textureDelta), v - textureDelta);
                GL11.glVertex3f(0.0450f, -0.0450f, 0.0f);
                GL11.glTexCoord2f((u + textureDelta), v);
                GL11.glVertex3f(0.0450f, 0.0450f, 0.0f);
                GL11.glTexCoord2f(u, v);
                GL11.glVertex3f(-0.0450f, 0.0450f, 0.0f);
            GL11.glEnd();
            GL11.glEndList();
        }
	}
	
	public static BitmapFont get() {
		return source;
	}
	
	/**
	 * Prepare OpenGL for Orthographic rendering.  The method will ensure that
	 * all states are saved.
	 */
	private void enterOrtho() {
		GL11.glDisable(GL11.GL_DEPTH_TEST);
		
		// Load the projection mode and save it's current state
		GL11.glMatrixMode(GL11.GL_PROJECTION); 
		GL11.glPushMatrix();
		GL11.glLoadIdentity();
		
		// Set up orthographic projection mode
		GL11.glOrtho(0, 800, 0, 600, -1, 1);
		
		// Enter model view mode
		GL11.glMatrixMode(GL11.GL_MODELVIEW);
		GL11.glPushMatrix();
		GL11.glLoadIdentity();
	}
	
	/**
	 * Leave Orthographic rendering in OpenGL.  Will restore all states saved
	 * by enterOrtho().
	 */
	private void leaveOrtho() {
		// Restore the state of the projection mode
		GL11.glMatrixMode(GL11.GL_PROJECTION);
		GL11.glPopMatrix();
		
		// Restore the state of the model view mode
		GL11.glMatrixMode(GL11.GL_MODELVIEW);
		GL11.glPopMatrix();
		GL11.glEnable(GL11.GL_DEPTH_TEST);
	}
	
	public void print(String msg, float x, float y) {
		enterOrtho();
		GL11.glTranslatef(x, y, 0.0f);
		
		// Ignore null value
		if (msg != null) {
			texture.bind();
			// Print the characters
			for(int i = 0; i < msg.length(); i++) {
				GL11.glCallList(listBase + msg.charAt(i));
				GL11.glTranslatef(1.0f, 0.0f, 0.0f);
            }			
		}
		leaveOrtho();	
	}
	
}


You might notice the TextureMgr.get().getTexture("res/Font.bmp"); bit in there. I basically took the image loading code out of here and put it in another class to make it all nicer. Also, the Texture object here is basically a class to hold the width/height of the image used for the texture, and to hold the texture id generated by the OpenGL engine. The texture.bind() method just calls GL11.glBindTexture(GL11.GL_TEXTURE_2D, this.id);, where this.id is the texture id given by OpenGL.

So basically, I call BitmapFont.get().print("blah blah", 100.0f, 100.0f); from some class, and it (should!) print the text to the display.  But it doesn't!  And the weird thing about the above code is that, if I remove the enterOrtho() and leaveOrtho() methods, the text displays fine! (Albeit it doesn't print using pixel coordinates, which I want!)

Does anyone have any idea what's up here? I'm quite flustered at the moment. I decided to ask you guys for help before I threw my monitor out the window haha.

Thanks in advance!

ps: I thnk I've included all the relevant info, if not tho lemme know and I'll give whatever you need!

avm1979

Hmm.  Looks like your code in enterOrtho and leaveOrtho is wrong.  After enterOrtho you'd like to end up in GL_PROJECTION matrix mode, but thats not what it's doing.  At least, this is my understanding of the problem.

Try the following for your enterOrtho and leaveOrtho methods (works for me for 2d stuff):

   
   public static void enterOrtho(int width, int height, int distance) {
      // store the current state of the renderer
      GL11.glPushAttrib(GL11.GL_DEPTH_BUFFER_BIT | GL11.GL_ENABLE_BIT | GL11.GL_COLOR_BUFFER_BIT);
      GL11.glPushMatrix();
      GL11.glLoadIdentity();
      GL11.glMatrixMode(GL11.GL_PROJECTION); 
      GL11.glPushMatrix();   
      
      // now enter orthographic projection
      GL11.glLoadIdentity();      
      GL11.glOrtho(0, width, height, 0, -distance, distance);

      GL11.glDisable(GL11.GL_DEPTH_TEST);
      GL11.glDisable(GL11.GL_LIGHTING);      
   }

   public static void leaveOrtho() {
      // restore the state of the renderer
      GL11.glPopMatrix();
      GL11.glMatrixMode(GL11.GL_MODELVIEW);
      GL11.glPopMatrix();
      GL11.glPopAttrib();
   }


It assumes that you're in GL_MODELVIEW mode before these are called (and thus leaveOrtho restores that).  Won't work if you're not (stack underflow).

By the way, you might want to check out http://www.angelcode.com/products/bmfont/ at some point.

It's a program that generates font textures out of your system fonts, and a nice xml descriptor to go with it.  It'll be a fair bit more work, but you'll end up w/ professional looking fonts (and won't be constrained to fixed point).

chisser98

Thanks for the post avm!

I ended up finding code similar to mine that worked - looks like the problem was that my quads were built for a non-orthographic surface (they were iddy-bitty), so they didn't display in Ortho mode!  yeesh.  I'm pretty sure I grew a few grays with this one.

Anywho, thanks for the help!