Slick Forums

Discuss the Slick 2D Library
It is currently Fri May 24, 2013 4:18 am

All times are UTC




Post new topic Reply to topic  [ 12 posts ] 
Author Message
PostPosted: Sat Oct 13, 2012 7:48 pm 
Offline

Joined: Sat Oct 13, 2012 7:39 pm
Posts: 7
Hello everybody. I've been lurking here for a bit and this seems like a great resource for me, since I've just started to get back into game programming. I'm still fairly new though, so if this isn't the right place for this question feel free to move it.

Anyway, here's my problem. I'll just present a very simple test case I'm working on, if any more info is needed I'll be happy to provide it.

I made 2 functions for drawing text, depending on if I'm using a font with a size in its filename or not:

Code:
public void drawString(String font, int x, int y, String str) {
   glEnable(GL_TEXTURE_2D);
   try { new AngelCodeFont("fonts/" + font + ".fnt", "fonts/" + font + "_0.png").drawString(x, y, str, Color.black); } catch (SlickException ex) { ex.printStackTrace(); }
   glDisable(GL_TEXTURE_2D);
}
   
public void drawString(String font, int size, int x, int y, String str) {
   glEnable(GL_TEXTURE_2D);
   try { new AngelCodeFont("fonts/" + font + "_" + size + ".fnt", "fonts/" + font + "_" + size + "_0.png").drawString(x, y, str, Color.black); } catch (SlickException ex) { ex.printStackTrace(); }
   glDisable(GL_TEXTURE_2D);
}


Now if I draw two strings like so

Code:
textDrawer.drawString("test1", 50, 50, "test 1!");
textDrawer.drawString("arial", 32, 50, 150, "test 2!");


it works as expected. However if I comment out "test1" and just leave the arial drawing command, the text doesn't come out right (blocky/unreadable or sometimes not at all). I can't even begin to imagine how this is even possible. Anyone have any insights?

Thanks so much in advance.


Top
 Profile  
 
PostPosted: Sun Oct 14, 2012 4:50 am 
Offline
Site Admin

Joined: Mon Dec 08, 2008 2:17 pm
Posts: 140
Hello saw7988,

The problem with your code snippet is that it creates a new font when you want to draw text.

It would be better to create the font once in the init method of the game state.

and then use that font to draw your text.

If you plan on using more then 2 fonts you could create a Map<String, Font> containing all your fonts.

If you will use these fonts in multiple places I suggest following the resource manager tutorial on the wiki.


Top
 Profile  
 
PostPosted: Sun Oct 14, 2012 7:05 am 
Offline
Slick Zombie

Joined: Sat Jan 27, 2007 7:10 pm
Posts: 1469
A. Don't create resources (images, fonts, etc) every frame in your game loop, otherwise your program will quickly run out of memory and crash.

B. Don't use glEnable -- instead use texture.bind and Texture.bindNone(). In this case you don't need any calls to glEnable or bind/bindNone since Font.drawString will do it all for you.


Top
 Profile  
 
PostPosted: Sun Oct 14, 2012 3:16 pm 
Offline

Joined: Sat Oct 13, 2012 7:39 pm
Posts: 7
Thanks for the responses guys! Unfortunately, I guess I should've cleaned up the code a little bit before posting my question, because I've been doing exactly what you guys have said, but the code has become a little bit dirtier in my efforts to debug. One of my incorrect hypotheses was that my problem had to do with font initialization, but instead I had just simultaneously removed my hashmap while adding in that first call to drawString.

My code started off with a HashMap in my TextDrawer class and it also didn't have the glEnable calls in there haha.

Any thoughts on why the 2 calls to drawString works, but only 1 call doesn't (this is with or without a hashmap, with or without loading the fonts each time, with and without glEnable calls, etc.)?

Thanks again!


Top
 Profile  
 
PostPosted: Sun Oct 14, 2012 4:19 pm 
Offline

Joined: Sat Oct 13, 2012 7:39 pm
Posts: 7
To clarify:

Code:
textDrawer.drawString("test1", 50, 50, "test 1!", Color.white);
textDrawer.drawString("arial", 32, 50, 150, "test 2!", Color.white);


Produces:
http://imageshack.us/a/img94/2336/outputsucc.png

While commenting out either line produces:
http://imageshack.us/a/img29/5157/outputfail.png

And my TextDrawer class is:
Code:
package _____;

import java.util.HashMap;

import org.newdawn.slick.AngelCodeFont;
import org.newdawn.slick.Color;
import org.newdawn.slick.SlickException;

public class TextDrawer {
   
   private HashMap<String,AngelCodeFont> fontMap;
   
   public TextDrawer() {
      fontMap = new HashMap<String,AngelCodeFont>();
      
      try {
         fontMap.put("arial_32", new AngelCodeFont("fonts/arial_32.fnt", "fonts/arial_32_0.png"));
         fontMap.put("test1", new AngelCodeFont("fonts/test1.fnt", "fonts/test1_0.png"));
         fontMap.put("test2", new AngelCodeFont("fonts/test2.fnt", "fonts/test2_0.png"));
         fontMap.put("test3", new AngelCodeFont("fonts/test3.fnt", "fonts/test3_0.png"));
         fontMap.put("test4", new AngelCodeFont("fonts/test4.fnt", "fonts/test4_0.png"));
      } catch (SlickException ex) {
         ex.printStackTrace();
      }
   }
   
   public void drawString(String font, int x, int y, String str, Color color) {
      fontMap.get(font).drawString(x, y, str, color);
   }
   
   public void drawString(String font, int size, int x, int y, String str, Color color) {
      fontMap.get(font + "_" + size).drawString(x, y, str, color);
   }

}


Top
 Profile  
 
PostPosted: Sun Oct 14, 2012 5:10 pm 
Offline
Slick Zombie

Joined: Sat Jan 27, 2007 7:10 pm
Posts: 1469
Are you using glEnable/glDisable/glBindTexture anywhere else in your program?

P.S. A little performance tip; try to pack as many fonts as you can into the same PNG file (i.e. under 1024x1024), then use getSubImage and pass the sub image to the AngelCodeFont constructor. This will result in far fewer texture binds, and much better speeds. :)


Top
 Profile  
 
PostPosted: Sun Oct 14, 2012 5:21 pm 
Offline

Joined: Sat Oct 13, 2012 7:39 pm
Posts: 7
Yea there's a ton of texture binding all over - this game uses a ton of textures. But didn't you say drawString will wrap all that up? Also, why would the one call to drawString fail but two calls works?


Top
 Profile  
 
PostPosted: Sun Oct 14, 2012 8:03 pm 
Offline
Slick Zombie

Joined: Sat Jan 27, 2007 7:10 pm
Posts: 1469
When you call slickTexture.bind() it will cache the last bound texture (to remove redundant OpenGL calls to glBindTexture). To give an example of the problem:

Code:
//this will bind texture A
myTextureA.bind();
draw(myTextureA);

//this will bind texture B
glBindTexture(GL_TEXTURE_2D, myTextureB.getTextureID());
draw(myTextureB);

//Problem: Slick thinks texture A is still bound!
//so if we try to draw texture A, it will ignore the glBindTexture call
//in other words: OpenGL will sample from texture B
draw(myTextureA);


The same issue can happen if you call glDisable and then try calling font.drawString; Slick will still think texture is enabled, and so the fonts will all appear gray (as in your screen shot).

You can call Texture.unbind() to clear the cach, and force a new call to glBindTexture next time you call texture.bind() or font.drawString (which calls texture.bind). You can call Texture.bindNone() to clear the state and glDisable texturing; e.g. if you were to render an untextured rectangle.

Some tips:
  • Don't use glBindTexture; instead use Slick's texture.bind() utility
  • If you need to disable texturing, use Texture.bindNone() instead of glEnable/glDisable
  • You should be aiming to minimize state changes per frame. This means you shouldn't be enabling or disabling things every time you render a sprite; nor should you be binding more textures per frame than necessary.
  • It's poor coding standards to have duplicate code. You shouldn't need to change hundreds of lines of code, since it should all point to a single source; e.g. drawSprite.
  • If you want a platform that is more closely integrated with the graphics layer, look into LibGDX.


Top
 Profile  
 
PostPosted: Sun Oct 14, 2012 8:51 pm 
Offline

Joined: Sat Oct 13, 2012 7:39 pm
Posts: 7
Thanks a lot davedes! You're spot on. It seems like changing all my glBindTextures to mytexture.bind() fixed my problem. You've explained things very well and your tips are great. I will be working to implement them all as much as I can and keep them in mind for the future as well.

Thanks again.


Top
 Profile  
 
PostPosted: Tue Oct 16, 2012 1:50 pm 
Offline

Joined: Sat Oct 13, 2012 7:39 pm
Posts: 7
Hi again. Not sure if I should've made a new thread, but I already have this one about AngelCodeFonts so I figured I'd just update it with a quick question.

Pretty much any settings I use (the glyph/outline/zero/one settings for a/r/g/b) give me solid opaque text on a transparent background. Is there any way I can get the text itself to have a specific transparency? Basically I want the text to fade away over x loops.

So keep the fully transparent background, but allow the text to have variable transparency?

Thanks guys.


Top
 Profile  
 
PostPosted: Tue Oct 16, 2012 5:24 pm 
Offline
Slick Zombie

Joined: Sat Jan 27, 2007 7:10 pm
Posts: 1469
Is this what you mean?
Code:
myColor.a = 0.5f; //draw text with 50% opacity
drawString(x, y, str, myColor);


Top
 Profile  
 
PostPosted: Tue Oct 16, 2012 6:48 pm 
Offline

Joined: Sat Oct 13, 2012 7:39 pm
Posts: 7
You are wonderful.

(thanks... once again :) )


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 12 posts ] 

All times are UTC


Who is online

Users browsing this forum: No registered users and 1 guest


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB® Forum Software © phpBB Group