glGenLists(256) not working correctly

Started by geekygenius, March 09, 2012, 06:42:15

Previous topic - Next topic

geekygenius

So, I am working on a game, where I have a few models, each represented by a display list. Since I need to be able to communicate with my players, I have looked into adding a text to my game. I found that the all famous "NeHe" tutorial. I think I have successfully modified the LWJGL port to fit my needs except for one crucial part, generating the display lists. After debugging, I found the problem that the base is 1, which is also the display list ID for another model, overwriting it when I try and create the letter. I don't know why, but the glGenLists(256) is returning 1, when it should be giving me something higher.

I have marked the important line of code with a comment, it's near the bottom. :D
Code:
package geekygenius.nutrality.gui;

import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.IntBuffer;

import org.lwjgl.opengl.GL11;

public class FontData {
    private static String fontResource = "resources/font.ttf";
    private static final Color OPAQUE_WHITE = new Color(0xFFFFFFFF, true);
    private static final Color TRANSPARENT_BLACK = new Color(0x00000000, true);

    private Font font;
    private int texture;
    private int base;

    private boolean built;

    public FontData(Font font) {
	this.font = font;
	built = false;
	buildFont();
    }

    public void displayText(String msg) {
	displayText(msg, 0, 0);
    }

    public void displayText(String msg, float x, float y) {
	GL11.glDisable(GL11.GL_LIGHTING);
	if (msg != null) {
	    GL11.glBindTexture(GL11.GL_TEXTURE_2D, texture);
	    for (int i = 0; i < msg.length(); i++) {
		GL11.glCallList(base + msg.charAt(i));
		GL11.glTranslatef(0.05f, 0.0f, 0.0f); // TODO Change this to get
						      // the width for non
						      // momospaced fonts.
	    }
	}
	GL11.glEnable(GL11.GL_LIGHTING);
    }

    public void buildFont() {
	if (!built) {
	    destroy();
	}
	built = true;

	BufferedImage fontImage;                        // image for creating the bitmap
	int bitmapSize = 512;                           // set the size for the bitmap texture
	boolean sizeFound = false;
	boolean directionSet = false;
	int delta = 0;
	float fontSize = 24;

	//Allocate Memory
	int width;
	int height;
	int lineWidth;
	// Find the size
	while (!sizeFound) {
	    font = font.deriveFont(fontSize);
	    // use BufferedImage.TYPE_4BYTE_ABGR to allow alpha blending
	    fontImage = new BufferedImage(bitmapSize, bitmapSize, BufferedImage.TYPE_4BYTE_ABGR);
	    Graphics2D g = (Graphics2D) fontImage.getGraphics();
	    g.setFont(font);
	    FontMetrics fm = g.getFontMetrics();
	    width = fm.stringWidth("W");
	    height = fm.getHeight();
	    lineWidth = (width > height) ? width * 16 : height * 16;
	    if (!directionSet) {
		if (lineWidth > bitmapSize) {
		    delta = -2;
		} else {
		    delta = 2;
		}
		directionSet = true;
	    }
	    if (delta > 0) {
		if (lineWidth < bitmapSize) {
		    fontSize += delta;
		} else {
		    sizeFound = true;
		    fontSize -= delta;
		}
	    } else if (delta < 0) {
		if (lineWidth > bitmapSize) {
		    fontSize += delta;
		} else {
		    sizeFound = true;
		    fontSize -= delta;
		}
	    }
	}


	/*
	 * Now that a font size has been determined, create the final image, set
	 * the font and draw the
	 * standard/extended ASCII character set for that font.
	 */
	// use BufferedImage.TYPE_4BYTE_ABGR to allow alpha blending
	fontImage = new BufferedImage(bitmapSize, bitmapSize, BufferedImage.TYPE_4BYTE_ABGR);
	Graphics2D g = (Graphics2D) fontImage.getGraphics();
	g.setFont(font);
	g.setColor(OPAQUE_WHITE);
	g.setBackground(TRANSPARENT_BLACK);
	FontMetrics fm = g.getFontMetrics();
	for (int i = 0; i < 256; i++) {
	    int x = i % 16;
	    int y = i / 16;
	    char ch[] = { (char) i };
	    String temp = new String(ch);
	    g.drawString(temp, (x * 32) + 1, (y * 32) + fm.getAscent());
	}

	/*
	 * The following code is taken directly for the LWJGL example code.
	 * It takes a Java Image and converts it into an OpenGL texture.
	 * This is a very powerful feature as you can use this to generate
	 * textures on the fly out
	 * of anything.
	 */
	// Flip Image
	AffineTransform tx = AffineTransform.getScaleInstance(1, -1);
	tx.translate(0, -fontImage.getHeight(null));
	AffineTransformOp op = new AffineTransformOp(tx, AffineTransformOp.TYPE_NEAREST_NEIGHBOR);
	fontImage = op.filter(fontImage, null);

	// Put Image In Memory
	ByteBuffer scratch = ByteBuffer.allocateDirect(4 * fontImage.getWidth() * fontImage.getHeight());

	byte data[] = (byte[]) fontImage.getRaster().getDataElements(0, 0, fontImage.getWidth(), fontImage.getHeight(),
		null);
	scratch.clear();
	scratch.put(data);
	scratch.rewind();

	// Create A IntBuffer For Image Address In Memory
	IntBuffer buf = ByteBuffer.allocateDirect(4).order(ByteOrder.nativeOrder()).asIntBuffer();
	GL11.glGenTextures(buf); // Create Texture In OpenGL

	GL11.glBindTexture(GL11.GL_TEXTURE_2D, buf.get(0));
	// Typical Texture Generation Using Data From The Image

	// Linear Filtering
	GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR);
	// Linear Filtering
	GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR);
	// Generate The Texture
	GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA, fontImage.getWidth(), fontImage.getHeight(), 0,
		GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, scratch);

	texture = buf.get(0);                           // Return Image Address In Memory

	base = GL11.glGenLists(256);                    // Storage For 256 Characters

//Important Line of code ^^ ============================================================

	/*
	 * 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 < 128; i++) {
	    float u = ((float) (i % 16)) / 16.0f;
	    float v = 1.f - (((float) (i / 16)) / 16.0f);
	    GL11.glNewList(base + i, GL11.GL_COMPILE);
	    GL11.glBindTexture(GL11.GL_TEXTURE_2D, texture);
	    GL11.glBegin(GL11.GL_QUADS);
	    GL11.glTexCoord2f(u, v);
	    GL11.glVertex3f(-0.0450f, 0.0450f, 0.0f);
	    GL11.glTexCoord2f((u + textureDelta), v);
	    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, v - textureDelta);
	    GL11.glVertex3f(-0.0450f, -0.0450f, 0.0f);
	    GL11.glEnd();
	    GL11.glEndList();
	}
    }

    public void destroy() {
	GL11.glDeleteLists(base, 256);
	GL11.glDeleteTextures(texture);
    }
}

This is set up in orthographic mode as follows:
glDisable(GL_LIGHTING);
	glDisable(GL_DEPTH_TEST);
	glMatrixMode(GL_PROJECTION);
	glPushMatrix();
	glLoadIdentity();
	glOrtho(0, 1280, 0, 720, -1, 1);
	glMatrixMode(GL_MODELVIEW);
	glPushMatrix();
	glLoadIdentity();

The 2D rendering does work with some basic quads I used for testing.

What am I doing wrong, and how can I fix it?


Fool Running

Does it work if you just generate one list at a time (i.e. call GL11.glGenLists(1) 256 times)? Are you absolutely sure that the display list for the other model is 1? Are you sure you haven't deleted the display list for that model? Are you getting any OpenGL errors?
Programmers will, one day, rule the world... and the world won't notice until its too late.Just testing the marquee option ;D

geekygenius

So, I tried generating the lists individually, but that didn't work. This is for rendering text on the HUD, which is above the main map, where as of now, I have three display lists, one for a tree, one for a town, and one for the whole map, which contains calls to the tree and town display lists. In debug mode, I found that the base was always returning as 1, which happened to be the same ID as the tree. When the map renders, the map is shown, but instead of showing trees and cities, it shows parts of the font, telling me that the display list was overwritten.

Fool Running

That's very strange. Are you sure you aren't getting any OpenGL errors?
Are you possibly using multiple contexts (i.e. creating the tree in one context and creating the text with another)?
Are you re-initializing the display between the times you create the display lists for the trees, cities and the time you create the display lists for the font?
If you don't do anything with the font, do you see the tree and cities?

If possible, more of your code would help.
Programmers will, one day, rule the world... and the world won't notice until its too late.Just testing the marquee option ;D