2D text in 3D environment problem

Started by Xenn, July 26, 2012, 09:42:06

Previous topic - Next topic

Xenn

Hello,

im dealing with some problems showing 2d text in a 3d environment.

The problem is, that the game (the movement of the character/camera) is getting very slow.
Maybe it's because i render HTML code into the environment.

Here the steps:

- The html code is loaded after i press return/enter (the text is a HTML code from the web and therefore not little)
- After i loaded the text, the game just starts to get slow, but the text is shown

What i also could notice is, that the HTML code is shown in a single line, but i first put the html code line by line with a "\n" into a string variable, then show it with pressing the return/enter key.

So my questions are, why does the problem appear?
Is it because of my grafikcard?
Or just because of the amount of text?
Or is it even because of my Java code?
And i also would to know, why the text is shown just in a single line.

Here the code of the render methode:

private boolean render() {
		GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT); // Clear
																			// The
																			// Screen
																			// And
																			// The
																			// Depth
																			// Buffer
		GL11.glLoadIdentity(); // Reset The View

		float x_m, y_m, z_m, u_m, v_m;
		float xtrans = -xpos;
		float ztrans = -zpos;
		float ytrans = -walkbias - 0.25f;
		float sceneroty = 360.0f - yrot;
		// lookupdown-=Mouse.getDY();
		int numTriangles;

		GL11.glRotatef(lookupdown, 1.0f, 0, 0);
		GL11.glRotatef(sceneroty, 0, 1.0f, 0);

		GL11.glTranslatef(xtrans, ytrans, ztrans);
		GL11.glBindTexture(GL11.GL_TEXTURE_2D, texture[filter]);

		numTriangles = sector1.numTriangles;

		// Process Each Triangle
		GL11.glColor3f(1f, 1f, 1f);
		for (int loop_m = 0; loop_m < numTriangles; loop_m++) {
			GL11.glBegin(GL11.GL_TRIANGLES);
			GL11.glNormal3f(0.0f, 0.0f, 1.0f);
			x_m = sector1.getTriangle()[loop_m].getVertex()[0].x;
			y_m = sector1.getTriangle()[loop_m].getVertex()[0].y;
			z_m = sector1.getTriangle()[loop_m].getVertex()[0].z;
			u_m = sector1.getTriangle()[loop_m].getVertex()[0].u;
			v_m = sector1.getTriangle()[loop_m].getVertex()[0].v;
			GL11.glTexCoord2f(u_m, v_m);
			GL11.glVertex3f(x_m, y_m, z_m);

			x_m = sector1.getTriangle()[loop_m].getVertex()[1].x;
			y_m = sector1.getTriangle()[loop_m].getVertex()[1].y;
			z_m = sector1.getTriangle()[loop_m].getVertex()[1].z;
			u_m = sector1.getTriangle()[loop_m].getVertex()[1].u;
			v_m = sector1.getTriangle()[loop_m].getVertex()[1].v;
			GL11.glTexCoord2f(u_m, v_m);
			GL11.glVertex3f(x_m, y_m, z_m);

			x_m = sector1.getTriangle()[loop_m].getVertex()[2].x;
			y_m = sector1.getTriangle()[loop_m].getVertex()[2].y;
			z_m = sector1.getTriangle()[loop_m].getVertex()[2].z;
			u_m = sector1.getTriangle()[loop_m].getVertex()[2].u;
			v_m = sector1.getTriangle()[loop_m].getVertex()[2].v;
			GL11.glTexCoord2f(u_m, v_m);
			GL11.glVertex3f(x_m, y_m, z_m);
			GL11.glEnd();
		}
		// Move One Unit Into The Screen

		
		
		//GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);  // Clear Screen And Depth Buffer
		GL11.glLoadIdentity(); 
		GL11.glTranslatef(0, 0.0f, 0);                                             // Reset The Current Modelview Matrix

		GL11.glRotatef(lookupdown, 1.0f, 0, 0);
		GL11.glRotatef(sceneroty, 0, 1.0f, 0);
        // Position The Text On The Screen
        GL11.glTranslatef(xtrans,ytrans, ztrans);                               // Move One Unit Into The Screen

        // Pulsing Colors Based On Text Position
        float red = 1.0f * ((float)Math.cos(cnt1));
        float green = 1.0f * ((float)Math.sin(cnt2));
        float blue = 1.0f - 0.5f * ((float)Math.cos(cnt1 + cnt2));
        GL11.glColor3f(0f, 0f, 0f);

        //format the floating point number to 2 decimal places
        numberFormat.setMaximumFractionDigits(2);
        numberFormat.setMinimumFractionDigits(2);

        buildFont2.glPrint(html);     // Print GL Text To The Screen
        cnt1 += 0.051f;                                                     // Increase The First Counter
        cnt2 += 0.005f;                                                     // Increase The Second Counter

     

		return true;
	}


If there are any other informations/code you need, just tell me, but i guess the problem should sit in this lines.

By the way, i'm learning with the NeHe tutorials (like the most of us i guess :))
I just started a week ago, so i'm sorry for the messy code and my bad english!


Greets

Xenn

moci

I think you're not showing us the important bit, namely how you actually render the text:

        buildFont2.glPrint(html);     // Print GL Text To The Screen


The problem only starts when running this command? I don't write "legacy" code so I can't really help you fix the problem but I would suggest you stop "learning" from NeHe and focus on OpenGL 3.2 and up. Maybe what you are using is not only old but also inefficient and since you are processing "bigger" strings it might slow down too much.

Xenn

Quote from: moci on July 26, 2012, 11:19:33
I think you're not showing us the important bit, namely how you actually render the text:

        buildFont2.glPrint(html);     // Print GL Text To The Screen



here the code of the class of buldFont:

package geo;

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 BuildFont {
	private static final Color OPAQUE_WHITE = new Color(0xFFFFFFFF, true);
	private static final Color TRANSPARENT_BLACK = new Color(0x00000000, true);

	private int textureFont;
	private int base;

	public void glPrint(String msg) { // Custom GL "Print" Routine

		if (msg != null) {
			GL11.glBindTexture(GL11.GL_TEXTURE_2D, textureFont);
			for (int i = 0; i < msg.length(); i++) {
				GL11.glCallList(base + msg.charAt(i));
				GL11.glTranslatef(0.05f, 0.0f, 0.0f);
			}
		}
	}

	public void glPrint(float x, float y, float z, String msg, int set) { // Where
																			// The
																			// Printing
																			// Happens
		if (set > 1) {
			set = 1;
		}
		 // Select Our Font
																// Texture
		//GL11.glEnable(GL11.GL_DEPTH_TEST); // Disables Depth Testing
		//GL11.glMatrixMode(GL11.GL_PROJECTION); // Select The Projection Matrix
		//GL11.glPushMatrix(); // Store The Projection Matrix
		//GL11.glLoadIdentity(); // Reset The Projection Matrix
		// GL11.glOrtho(0, 640, 0, 480, -1, 1); // Set Up An Ortho Screen
		//GL11.glMatrixMode(GL11.GL_MODELVIEW); // Select The Modelview Matrix
		//GL11.glPushMatrix(); // Store The Modelview Matrix
		//GL11.glLoadIdentity(); // Reset The Modelview Matrix 
		GL11.glTranslatef(x, y, z); // Position The Text (0,0 - Bottom Left)
		int baseOffset = base - 32 + (128 * set); // Choose The Font Set (0 or
													// 1)
		GL11.glBindTexture(GL11.GL_TEXTURE_2D, textureFont);
		for (int i = 0; i < msg.length(); i++) {
			GL11.glCallList(base + msg.charAt(i));
			GL11.glTranslatef(0.05f, 0.0f, 0.0f);
		}
		//GL11.glMatrixMode(GL11.GL_PROJECTION); // Select The Projection Matrix
		//GL11.glPopMatrix(); // Restore The Old Projection Matrix
		//GL11.glMatrixMode(GL11.GL_MODELVIEW); // Select The Modelview Matrix
		//GL11.glPopMatrix(); // Restore The Old Projection Matrix
		//GL11.glEnable(GL11.GL_DEPTH_TEST); // Enables Depth Testing
	}

	public void setPosition(float x, float y, float z) {
		GL11.glTranslatef(x, y, z);
	}

	public BuildFont() { // Build Our Bitmap Font
		Font font; // Font object

		/**
		 * Note that I have set the font to Courier New. This font is not
		 * guraunteed to be on all systems. However it is very common so it is
		 * likely to be there. You can replace this name with any named font on
		 * your system or use the Java default names that are guraunteed to be
		 * there. Also note that this will work well with monospace fonts, but
		 * does not look as good with proportional fonts.
		 */

		String fontName = "Helvetica"; // Name of the font to use
		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;
		int fontSize = 24;

		/*
		 * To find out how much space a Font takes, you need to use a the
		 * FontMetrics class. To get the FontMetrics, you need to get it from a
		 * Graphics context. A Graphics context is only available from a
		 * displayable surface, ie any class that subclasses Component or any
		 * Image. First the font is set on a Graphics object. Then get the
		 * FontMetrics and find out the width and height of the widest character
		 * (W). Then take the largest of the 2 values and find the maximum size
		 * font that will fit in the size allocated.
		 */
		while (!sizeFound) {
			font = new Font(fontName, Font.PLAIN, fontSize); // Font Name
			// 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();
			int width = fm.stringWidth("W");
			int height = fm.getHeight();
			int 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.
		 */
		font = new Font(fontName, Font.BOLD, fontSize); // Font Name
		// 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);

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

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

		/*
		 * 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(base + i, GL11.GL_COMPILE);
			GL11.glBindTexture(GL11.GL_TEXTURE_2D, textureFont);
			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();
		}
	}
}



Quote from: moci on July 26, 2012, 11:19:33
The problem only starts when running this command? I don't write "legacy" code so I can't really help you fix the problem but I would suggest you stop "learning" from NeHe and focus on OpenGL 3.2 and up. Maybe what you are using is not only old but also inefficient and since you are processing "bigger" strings it might slow down too much.

the problem starts after handing over the html variable to buildFont (notice that before that, the html code were put into the html-string variable)
after i set html=""; everything is fine again

Hmm yeah, OpenGL 1.1 is realy old, but this tutorials realy helped me much till now.
But how big is the difference when i get started with OGL 3.2?
Is the syntax of 3.2 similar with 1.1?
I just know that the performance is better and there are more functions or smth like that...

moci

Again, I don't write legacy OpenGL code (pre 3.2/2.0) so I couldn't tell you what's wrong. Try printing smaller pieces of text and see when you notice a big performance drop.

The main difference between "legacy OpenGL" en "Core OpenGL" 3.2 and up is the deletion of the fixed function pipeline and matrix stack. For instance in legacy OpenGL you can define up to 8 lights without knowing anything of how to do lighting calculation. In "Core OpenGL" anything visually has to be done via Shaders (vertex shaders, geometry shaders and fragment/pixel shaders) so you'll have to do all of that yourself. The deletion of the matrix stack (glRotate, glPopMatrix, glPushMatrix, ...) also means you'll have to do your own matrix calculation (LWJGL provides these mathematical functions as well) and push the calculations to the Shaders etc...

OpenGL 1.1 and what have you is still valid because there is a compatibility profile newer versions of OpenGL use which do not have these things deleted but it's a good idea specially when you start learning OpenGL to learn what the future OpenGL code will look like. Why learn the "old" way? Maybe it's easier but you're just fooling yourself as eventually everyone will move on and you'll have to relearn everything once again. It's a personal opinion but for me it's a no brainer.

I have uploaded a number of basic OpenGL 3.2 and up tutorials to the WIKI but none have text rendering. If you want to have LWJGL examples of newer OpenGL code I suggest you look at them: http://lwjgl.org/wiki/index.php?title=Main_Page .

Fool Running

Quote from: Xenn on July 26, 2012, 09:42:06
So my questions are, why does the problem appear?
Is it because of my grafikcard?
Or just because of the amount of text?
Or is it even because of my Java code?
And i also would to know, why the text is shown just in a single line.

The reason it's slow is probably because you have too much text (like moci said). If you're rendering more then 1000 characters like that, it's going to be fairly slow (especially if you have a slow graphics card).

The reason it's not showing on multiple lines is because the glPrint() method doesn't handle them (you would need to add special logic in the loop that loops over the characters in the string to change the position to another line when finding a '\n' character).
Programmers will, one day, rule the world... and the world won't notice until its too late.Just testing the marquee option ;D

Xenn

ouh okay
my biggest respect to you for programming with core opengl D: sounds very hard

you are right, maybe i should start from now on with a higher version of opengl
but then i will get in trouble with using the text i guess, i need that realy much for one of my projects :/
that's also a reason why i prefered the NeHe tutorials, i hope there are some other good tutorials on the web handling text

thank you both for your help!