Slick-Util (Part 3) - TrueType Fonts for LWJGL

Intro
Part 1 - Loading Images for LWJGL
Part 2 - Loading Sounds for LWJGL
Part 3 - TrueType Fonts for LWJGL

Why is a Library needed for Fonts?
OpenGL has no built-in support for fonts. In order to display fonts you will need to manually implement such support. It can be pretty tricky to implements fonts correctly especially as there are many different ways and techniques to do this in OpenGL. Using bitmaps to display fonts in OpenGL is probably the most popular method.

True Type Font Format
The True Type Font Format (.ttf) is the most widely used format to store and share fonts. There are tons of sites out there which supply fonts in this format for free, e.g.:

http://www.dafont.com/
http://www.1001freefonts.com/
http://www.urbanfonts.com/

Basics
Slick-Util uses Java's built in AWT Font support to load the fonts, so be sure to be familar with the AWT's Font class. You can use either the default built in java fonts or load external ttf files.

The Slick-Util library will convert the AWT Font so that it can be used with OpenGL. The fonts are stored and drawn through slick's TrueTypeFont class.

To load a True Type Font you simply do the following:

TrueTypeFont font;
TrueTypeFont font2;
 
public void init() {
	// load a default java font
	Font awtFont = new Font("Times New Roman", Font.BOLD, 24);
	font = new TrueTypeFont(awtFont, false);
 
	// load font from a .ttf file
	try {
		InputStream inputStream	= ResourceLoader.getResourceAsStream("myfont.ttf");
 
		Font awtFont2 = Font.createFont(Font.TRUETYPE_FONT, inputStream);
		awtFont2 = awtFont2.deriveFont(24f); // set font size
		font2 = new TrueTypeFont(awtFont2, false);
 
	} catch (Exception e) {
		e.printStackTrace();
	}	
}

and its equally simple to render them onto the screen.

public void render() {
	font.drawString(100, 50, "THE LIGHTWEIGHT JAVA GAMES LIBRARY", Color.yellow);
	font2.drawString(100, 100, "NICE LOOKING FONTS!", Color.green);
}

Below is a full working example on how to use the ttf fonts with LWJGL using slick-util.

import java.awt.Font;
import java.io.InputStream;
 
import org.lwjgl.LWJGLException;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.lwjgl.opengl.GL11;
 
import org.newdawn.slick.Color;
import org.newdawn.slick.TrueTypeFont;
import org.newdawn.slick.util.ResourceLoader;
 
public class FontExample {
 
	/** The fonts to draw to the screen */
	private TrueTypeFont font;
	private TrueTypeFont font2;
 
	/** Boolean flag on whether AntiAliasing is enabled or not */
	private boolean antiAlias = true;
 
	/**
	 * Start the test 
	 */
	public void start() {
		initGL(800,600);
		init();
 
		while (true) {
			GL11.glClear(GL11.GL_COLOR_BUFFER_BIT);
			render();
 
			Display.update();
			Display.sync(100);
 
			if (Display.isCloseRequested()) {
				Display.destroy();
				System.exit(0);
			}
		}
	}
 
	/**
	 * Initialise the GL display
	 * 
	 * @param width The width of the display
	 * @param height The height of the display
	 */
	private void initGL(int width, int height) {
		try {
			Display.setDisplayMode(new DisplayMode(width,height));
			Display.create();
			Display.setVSyncEnabled(true);
		} catch (LWJGLException e) {
			e.printStackTrace();
			System.exit(0);
		}
 
		GL11.glEnable(GL11.GL_TEXTURE_2D);
		GL11.glShadeModel(GL11.GL_SMOOTH);        
		GL11.glDisable(GL11.GL_DEPTH_TEST);
		GL11.glDisable(GL11.GL_LIGHTING);                    
 
		GL11.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);                
        GL11.glClearDepth(1);                                       
 
        GL11.glEnable(GL11.GL_BLEND);
        GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
 
        GL11.glViewport(0,0,width,height);
		GL11.glMatrixMode(GL11.GL_MODELVIEW);
 
		GL11.glMatrixMode(GL11.GL_PROJECTION);
		GL11.glLoadIdentity();
		GL11.glOrtho(0, width, height, 0, 1, -1);
		GL11.glMatrixMode(GL11.GL_MODELVIEW);
	}
 
	/**
	 * Initialise resources
	 */
	public void init() {
		// load a default java font
		Font awtFont = new Font("Times New Roman", Font.BOLD, 24);
		font = new TrueTypeFont(awtFont, antiAlias);
 
		// load font from file
		try {
			InputStream inputStream	= ResourceLoader.getResourceAsStream("myfont.ttf");
 
			Font awtFont2 = Font.createFont(Font.TRUETYPE_FONT, inputStream);
			awtFont2 = awtFont2.deriveFont(24f); // set font size
			font2 = new TrueTypeFont(awtFont2, antiAlias);
 
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
 
	/**
	 * Game loop render
	 */
	public void render() {
		Color.white.bind();
 
		font.drawString(100, 50, "THE LIGHTWEIGHT JAVA GAMES LIBRARY", Color.yellow);
		font2.drawString(100, 100, "NICE LOOKING FONTS!", Color.green);
	}
 
	/**
	 * Main method
	 */
	public static void main(String[] argv) {
		FontExample fontExample = new FontExample();
		fontExample.start();
	}
}

You should get an output similar to the image below.

Additional Credit
Kevin Glass for writing the Slick Library and initial example code.

Intro
Part 1 - Loading Images for LWJGL
Part 2 - Loading Sounds for LWJGL
Part 3 - TrueType Fonts for LWJGL

Comments

not sure why but my text is upside down. any ideas?

Anonymous Ninja
Tue, 09/01/2015 - 12:56

Where I can get UnicodeFont class? I download lib from here http://slick.ninjacave.com/slick-util/ and there is no UnicodeFont class, only TrueTypeFont.

Anonymous Ninja
Wed, 03/19/2014 - 16:57

Ok, I found solution. I downloaded "Slick-Util library only", and where is no UnicodeFont, but it exist in full library in "Full Download".

Anonymous Ninja
Thu, 03/20/2014 - 13:00

Thanks x share this solution!

Anonymous Ninja
Tue, 09/22/2015 - 19:55

Help me guys!

Exception in thread "main" java.lang.ExceptionInInitializerError
Caused by: java.lang.RuntimeException: No OpenGL context found in the current thread.
at org.lwjgl.opengl.GLContext.getCapabilities(GLContext.java:124)
at org.lwjgl.opengl.GL11.glGetError(GL11.java:1289)
at org.newdawn.slick.opengl.renderer.ImmediateModeOGLRenderer.glGetError(ImmediateModeOGLRenderer.java:384)
at org.newdawn.slick.opengl.GLUtils.checkGLContext(GLUtils.java:17)
at org.newdawn.slick.TrueTypeFont.(TrueTypeFont.java:92)
at org.newdawn.slick.TrueTypeFont.(TrueTypeFont.java:112)
at mainGame.MainLoop.(MainLoop.java:21)

Anonymous Ninja
Wed, 11/06/2013 - 19:14

I got this too when I tried to initialize my TrueTypeFont before I did the OpenGL initialization. Once I created the TrueTypeFont(s) after all OpenGL initialization, my problem went away.

Anonymous Ninja
Tue, 01/07/2014 - 05:50

I used this code for creating fonts but my text renders without the line breaks. Can anyone help me?

Anonymous Ninja
Sun, 10/27/2013 - 22:35

I'm following the tutorial and I'm getting this weird highlighting that kind of fades in:

http://i.imgur.com/8CsjH35.png

Any Idea what would cause this?

Anonymous Ninja
Sun, 09/01/2013 - 23:38

I got this as well, until I added to the beginning of each loop this:

GL11.glClear(GL11.GL_COLOR_BUFFER_BIT);

Put it at the top of your render code.

Anonymous Ninja
Tue, 01/07/2014 - 05:47

great tutorial,but it did'nt draw the unicode, is there any tutorial for unicode?

Anonymous Ninja
Tue, 05/07/2013 - 07:39

I have used this method of adding text into a project of mine, but am currently struggling to figure out how to center the text within the screen. Any ideas?

Anonymous Ninja
Sun, 02/17/2013 - 01:07

I came here for this answer as well. I answered two other questions in this thread and then figured out this next one:

        String t = "Centered Text";
        TrueTypeFont font = getFont();
        int width = getDisplayWidth(); // your screen width
        int height = getDisplayHeight(); // your screen height
        float x = (float)width/2;
        float y = (float)height/2;
        float stringWidth = font.getWidth(t);
        float stringHeight = font.getHeight(t);
        lwjglEngine.getFont().drawString(x - stringWidth, y - stringHeight, t, Color.yellow);

Obviously getFont(), getDisplayWidth(), and getDisplayheight() are just placeholders for however you are storing your TrueTypeFont and your screen size.

Anonymous Ninja
Tue, 01/07/2014 - 06:04

Thanks for writing this font tutorial. Do you happen to have the Eclipse project for this online?
I've got the native libraries for LWJGL set up properly and working but when I add in slick-util.jar to the build path and try to run your example it crashes with what looks to be a native linking error.
Did you need to do any extra native linking to use Slick-Util?

Exception in thread "main" java.lang.UnsatisfiedLinkError: no sljava in java.library.path
at java.lang.ClassLoader.loadLibrary(Unknown Source)
at java.lang.Runtime.loadLibrary0(Unknown Source)
at java.lang.System.loadLibrary(Unknown Source)
at com.actividentity.sso.javasso.SSOLoginScriptRunner.(SSOLoginScriptRunner.java:777)
at com.actividentity.sso.javasso.Logger.getLogLevel(Logger.java:75)
at com.actividentity.sso.javasso.Logger.(Logger.java:80)
at com.actividentity.sso.javasso.awt_swing.JavaSSOHook.(JavaSSOHook.java:166)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source)
at java.lang.reflect.Constructor.newInstance(Unknown Source)
at java.lang.Class.newInstance0(Unknown Source)
at java.lang.Class.newInstance(Unknown Source)
at java.awt.Toolkit.loadAssistiveTechnologies(Unknown Source)
at java.awt.Toolkit.getDefaultToolkit(Unknown Source)
at sun.java2d.d3d.D3DGraphicsDevice.(Unknown Source)
at sun.java2d.SurfaceManagerFactory.createCachingManager(Unknown Source)
at sun.awt.image.SurfaceManager.getManager(Unknown Source)
at sun.java2d.SurfaceData.getDestSurfaceData(Unknown Source)
at sun.java2d.SunGraphicsEnvironment.createGraphics(Unknown Source)
at java.awt.image.BufferedImage.createGraphics(Unknown Source)
at java.awt.image.BufferedImage.getGraphics(Unknown Source)
at org.newdawn.slick.TrueTypeFont.createSet(TrueTypeFont.java:183)
at org.newdawn.slick.TrueTypeFont.(TrueTypeFont.java:98)
at org.newdawn.slick.TrueTypeFont.(TrueTypeFont.java:112)
at FontExample.init(FontExample.java:85)
at FontExample.start(FontExample.java:27)
at FontExample.main(FontExample.java:115)

Anonymous Ninja
Sun, 04/15/2012 - 07:31

That does not look like an error coming from LWJGL, according to the exception its the file SSOLoginScriptRunner.java which is trying to load some native files.

admin
Sun, 04/15/2012 - 11:48

Found the cause of the problem. The version of LWJGL I was using wasn't compatible with Slick. Downgraded and it works now. Weird how some secure login package got involved here...

Anonymous Ninja
Tue, 04/17/2012 - 14:36