Schabby's Blog
Reserve Orbital Defence Commander

In order to get up and running with OpenGL and LWJGL, one need to understand the most basic setup of LWJGL. This is important to understand because all following examples will be based on that.

LWJGL Setup

  1. Fire up your favourite IDE (I am using Eclipse), create a project and make shure you got the following two folders:
    • lib
    • native/windows

    The lib folder will contain the LWJGL JAR files, while native/windows will hold LWJGLs precompiled native binaries. In my case it's windows. This obviously can differ for you (Mac, *nix, etc).

  2. Next, download LWJGL from their official website. Make sure you download the right one for your OS.
  3. Then, extract the contents of the download archive, such that
    • The folder lib contains
      • lwjgl_util.jar
      • lwjgl.jar

      Mac users be warned, you may need additional JARs to get started (see LWJGLs official installation page).

    • The folder native/windows contains the native, pre-compile binaries. On Windows 64 bit, this is
      • lwjgl.dll
      • lwjgl64.dll

      These two are important for OpenGL. But since you are at it, you may also add the rest, even though we will not use the right away:

      • jinput-dx8_64.dll
      • jinput-dx8.dll
      • jinput-raw_64.dll
      • jinput-raw.dll
      • OpenAL32.dll
      • OpenAL64.dll
  4. Add the JARs to the classpath of your project.
  5. Create a class and copy-paste the code at the bottom of this page.
  6. Run the main method of the class. You should see a window with a black background! :)

This is what you should see when running the program:

Simple Hello World LWJGL setup

If you get the error message

Exception in thread "main" java.lang.UnsatisfiedLinkError: no lwjgl in java.library.path

then LWJGL can not find the corresponding native binaries. Make sure you got our native libs (eg. .dll) in the folder native/windows of you working directory when you start Java. Also, you may add -Djava.library.path=[path to your native binaries] as parameters when calling the Java executable.

In case you get the error message

org.lwjgl.LWJGLException: Could not create context (WGL_ARB_create_context)

during the initialization phase, the your OpenGL driver does most likely not support OpenGL 4.0. Try to set

ContextAttribs contextAtrributes = new ContextAttribs(3, 2);

which sets the OpenGL Version to 3.2.

I realize Maven can help you on that, but I'd recommend doing things manually first.

Complete Source Code

Here comes the full source code as copy/paste template. A step-by-step explanation follows below the code chunk.

package de.schabby.tutorial.settinguplwjgl;
 
import org.lwjgl.LWJGLException;
import org.lwjgl.opengl.*;
 
public class BasicLwjglExample 
{
 
	/**
	 * Initialize OpenGL through LWJGL. Starts the
	 * Display with a fixed resolution of 640x480.
	 */
	public void initOpenGL(String windowTitle)
	{
		try
		{
			// width and height of window and view port
			int width	= 640;
			int height	= 480;
 
			// set up window and open it
			Display.setDisplayMode(new DisplayMode(width, height));
 
			// limit video card to refresh rate of screen (60 Hertz on most LCDs)
			Display.setVSyncEnabled(true);
 
			// set windows title
			Display.setTitle(windowTitle);
 
			// set up OpenGL to run in forward-compatible mode
			// so that using deprecated functionality will
			// throw an error. This ensures that we are making
			// use of OpenGL 
			PixelFormat pixelFormat = new PixelFormat();
			ContextAttribs contextAtrributes = new ContextAttribs(4, 0);
			contextAtrributes.withForwardCompatible(true);
			contextAtrributes.withProfileCore(true);
			Display.create(pixelFormat, contextAtrributes);
 
			// initialize basic OpenGL stuff
			GL11.glViewport(0, 0, Display.getDisplayMode().getWidth(), Display.getDisplayMode().getHeight());
			GL11.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
 
			System.out.println("Welcome to Schabbys '"+windowTitle+"'. You are running OpenGL version ["+GL11.glGetString(GL11.GL_VERSION)+"].");
		}
		catch( LWJGLException lwjglException )
		{
			throw new RuntimeException("Aaargh, could not initiate LWJGL", lwjglException);
		}
	}
 
	/**
	 * initialize OpenGL and call the run method
	 */
	public void initAndRun(String windowTitle)
	{
		initOpenGL(windowTitle);
		run();
	}
 
	/**
	 * Run the actual program. This method will be overriden in
	 * future tutorial.
	 */
	public void run()
	{
		// game loop
		while( Display.isCloseRequested() == false )
		{
			// this is were all the drawing will take 
			// place soon...
			// But for now, we just display a black
			// rectangle.
 
 
			// swap buffers and sync frame rate to 60 fps
			Display.update();
			Display.sync(60);
		}
 
		// close Display and stop internal update thread
		Display.destroy();
	}
 
	public static void main(String[] programArguments)
	{
		BasicLwjglExample example = new BasicLwjglExample();
		example.initAndRun("Basic LWJGL Example");
	}
 
}

Code Explanation

Let's have a closer look at a the code given above. It will help you understand the very elementary things about LWJGL. We will later use this class to extend from it in order to re-use the initialization part for LWJGL.

The main method starts the program and calls initAndRun(). initAndRun() takes as a parameter the title of the to-be-opened window and calls the two methods initOpenGL() and run(). So far this is not very challenging.

public static void main(String[] programArguments)
{
	BasicLwjglExample example = new BasicLwjglExample();
	example.initAndRun("Basic LWJGL Example");
}
 
public void initAndRun(String windowTitle)
{
	initOpenGL(windowTitle);
	run();
}

The initOpenGL() method does the actual work of initializing LWJGL (and by thus OpenGL).

public void initOpenGL(String windowTitle)
{

We first set up the Display. You can think of it as your Window or Screen (of you are in fullscreen mode). The display mode defines the pixel format, resolution, fullscreen capability and frequency. Here, however, we just set the size of the window to 640x480 pixels and dont use fullscreen mode.

	Display.setDisplayMode(new DisplayMode(640, 480));

In addition, we align the refresh frequency of the image to the video card and screen capabilities, which is usually 60 Hertz for normal LCD screens. 60 Hertz means 60 images (aka. frames) per second.

	Display.setVSyncEnabled(true);

We set the window title to the methods windowTitle parameter.

	Display.setTitle(windowTitle);

Now the next lines are interesting. We set LWJGL/OpenGL to run in forward compatibilty mode for OpenGL 4. This means in essence, that we will get an error, every time we use a functionality in OpenGL that is marked as deprecated. Or in other words, we switch OpenGL to run in "OpenGL-4.0-and-newer-only" mode.

	PixelFormat pixelFormat = new PixelFormat();
	ContextAttribs contextAtrributes = new ContextAttribs(4, 0);
	contextAtrributes.withForwardCompatible(true);
	contextAtrributes.withProfileCore(true);

Now we can finally create and open the Display, using the aforementioned settings.

	Display.create(pixelFormat, contextAtrributes);

Until now, we were only setting up LWJGL. Now that LWJGL and OpenGL is up and running, we can talk to OpenGL. You can differentiate OpenGL calls (or in short gl calls) from other stuff by the indistinguishable naming pattern: glNameOfFunction. All gl calls are static in LWJGL and reside in one of many GLxx classes, where xx denotes the version number of OpenGL in which the function has been introduced.

In the below two lines, we are first making a call to set up the viewport to range from lower (!) left corner to the upper right, spanning the width and height of the Display. What glViewport exactly does internally is not in the scope of this tutorial and will be explained later. You need to live with the explanation for now, that it sets up the drawing area of OpenGL to cover the same area as the Display.

The second gl call is glClearColor. OpenGL has a special call to flush the buffer in which the images are drawn and repaint it with a previously specified color. This sets this clearing color to black.

	GL11.glViewport(0, 0, Display.getDisplayMode().getWidth(), Display.getDisplayMode().getHeight());
	GL11.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
}

Game Loop

This is it for the set up part. Let us now check out the actual run() method.

public void run()
{

To understand game development, you need to realize one important architectural peculiarity: All games have a game loop. They are the central kernel of each game a usually follow this pattern:

  1. read input from keyboard, mouse, network, etc.
  2. process input and update model (ie. data structure that holds the state of the game)
  3. render image

These three steps are repeated in each cycle. Each cycle draws an image (aka. frame) from scratch, even though the final result may not be very different from the former image. Since the cycle is executed very fast and the changes are very small, you get the impression of moving images. Well, as long as the cycle rate (aka. frame rate) is high enough, which is normally the case for rates above 30 frames per second.

Let us consider a first person shooter as a quick example. At start-up, you see a scene rendered on your 2D screen. In each cycle, the program reads the currently pressed keys (eg. the "move forward" key) and processes that input in the second stage. Since you pressed the "move forward" key, the second stage would update the players position by one step in the walking direction. In stage three, the updated model would be rendered on an image, showing the almost identical scene with the little difference that the player has done one step forward.

All the game logic happens in step two. Often (especially in real-time simulations) there is much more going on than just updating player positions, such as running physics simulations, processing queued commands and so on. The important pattern is the step-wise update procedure. You only compute the next step, mostly never two or more cycles ahead because you cannot know what the model will look like in the very next cycle. This method is also sometimes referred to as Euler Method.

Game loops and especially OpenGL imply single threaded applications. It occurs often, however, that peripherical stuff such as network, sound etc. is dealt with in individual threads which need a shared point of synchronization with the main thread that runs the game loop. OpenGL does not go well with multi-threading and I honestly recommend to avoid it where you can.

A noteworthy thing about turn-based games: Dont mix turns with cycles. Turns are usually handled independently from time and the game loop, because they are usually synchronized to game events such as "user ended turn" or "all units moved". While the players are waiting for a turn to end, the images are still updates which means that the game loop still runs. Cycles on the other hand have a clearly defined, short-lived time frame in which they are supposed to get done.

There is a lot that one could write about game loops, how different games deal with "time" and how games organize their data structures. It is an extremely interesting topic, but beyond the scope of this tutorial (and honestly, I am not an expert, just an enthusiast).

The code below shows the most basic game loop one could think of. It runs as long as the window is shown and does nothing except to update the Display in the update() method and wait a bit during sync(60) to keep the frame rate on 60 Hertz.

	while( Display.isCloseRequested() == false )
	{
		// do nothing...
 
		Display.update();
		Display.sync(60);
	}

Once the close button on the Display has been pressed, the while loop will exit and we shut down LWJGL.

	Display.destroy();
}

The end. I hope you found the tutorial interesting. Please leave a message if you have questions and think the tutorial could need improvement.

Additional Resources

  1. LWJGLs official installation page. Very helpful.
  2. LWJGL. Lots of awesome documentation, forum and stuff around LWJGL. Note that LWJGL is not only a OpenGL binding. From their official website I quote "The Lightweight Java Game Library (LWJGL) is a solution aimed directly at professional and amateur Java programmers alike to enable commercial quality games to be written in Java. LWJGL provides developers access to high performance crossplatform libraries such as OpenGL (Open Graphics Library), OpenCL (Open Computing Language) and OpenAL (Open Audio Library) allowing for state of the art 3D games and 3D sound.
  3. a popular alternative to LWJGL is JOGL - Java OpenGL Binding. I however prefer LWJGL for being tailored for games. If you just want pure OpenGL, you can also go with JOGL, it's very good too and I don't follow any religious war here. JOGL and LWJGL both do OpenGL, but for game development I started to like LWJGL a bit better.
  4. http://www.java-gaming.org - another nice forum for Java game developer enthusiasts.

Post Comment

Please notice: Comments are moderated by an Admin.