Hello!
I've wanted to create a simple tile-based game for a while, and recently I've had the time to do it. I originally wrote said game using Java2D, and then decided for performance reasons to switch to LWJGL. Since then, I've run across a problem which strikes me as exceedingly newbish, yet which I seem to be unable to solve.
I am trying to initialize a 480x320p frame, and paint an image of the same dimensions on it using LWJGL.
I am utilizing the following code:
public class TestApplet extends Applet {
/**
* The Canvas where the LWJGL Display is added
*/
Canvas display_parent;
/**
* Thread which runs the main game loop
*/
Thread gameThread;
int width = 480;
int height = 320;
public TestApplet() {
init();
}
/**
* Once the Canvas is created its add notify method will call this method to
* start the LWJGL Display and game loop in another thread.
*/
public void startLWJGL() {
try {
Display.setParent(display_parent);
// get modes
Display.setTitle("Test");
Display.setFullscreen(false);
Display.create();
// enable textures since we're going to use these for our sprites
glEnable(GL_TEXTURE_2D);
// disable the OpenGL depth test since we're rendering 2D graphics
glDisable(GL_DEPTH_TEST);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, width, height, 0, -1, 1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glViewport(0, 0, width, height);
} catch (LWJGLException e) {
e.printStackTrace();
}
gameThread = new Thread() {
public void run() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
new TextureLoader().getSprite("Test.png").draw(0, 0);
}
};
gameThread.start();
}
/**
* Tell game loop to stop running, after which the LWJGL Display will be destoryed.
* The main thread will wait for the Display.destroy() to complete
*/
private void stopLWJGL() {
// TODO some stopping code here
}
/**
* Applet Destroy method will remove the canvas, before canvas is destroyed it will notify
* stopLWJGL() to stop main game loop and to destroy the Display
*/
public void destroy() {
remove(display_parent);
super.destroy();
System.out.println("Clear up");
}
/**
* initialise applet by adding a canvas to it, this canvas will start the LWJGL Display and game loop
* in another thread. It will also stop the game loop and destroy the display on canvas removal when
* applet is destroyed.
*/
public void init() {
setLayout(new BorderLayout());
try {
display_parent = new Canvas() {
public void addNotify() {
super.addNotify();
startLWJGL();
}
public void removeNotify() {
stopLWJGL();
super.removeNotify();
}
};
display_parent.setSize(getWidth(), getHeight());
add(display_parent);
display_parent.setFocusable(true);
display_parent.requestFocus();
display_parent.setIgnoreRepaint(true);
setVisible(true);
} catch (Exception e) {
System.err.println(e);
throw new RuntimeException("Unable to create display");
}
}
}
Essentially, it is the same as the example on LWJGL's Github example folder, yet with no logic but painting a screen constantly.
And yet, whenever I attempt to run the above snippet, I am hit with the following exceptions:
Exception in thread "Thread-5" java.lang.NullPointerException
at org.lwjgl.opengl.GL11.glClear(GL11.java:586)
at amber.TestApplet$1.run(TestApplet.java:69)
java.lang.RuntimeException: Unable to create display
at amber.TestApplet.init(TestApplet.java:135)
at sun.applet.AppletPanel.run(AppletPanel.java:424)
at java.lang.Thread.run(Thread.java:662)
Caused by: java.lang.IllegalStateException: From thread Thread[thread applet-amber.TestApplet,4,file:/a/path/-threadGroup]: Thread[Thread-3,4,] already has the context current
at org.lwjgl.opengl.ContextGL.checkAccess(ContextGL.java:184)
at org.lwjgl.opengl.ContextGL.makeCurrent(ContextGL.java:189)
at org.lwjgl.opengl.DrawableGL.makeCurrent(DrawableGL.java:110)
at org.lwjgl.opengl.Display.makeCurrent(Display.java:731)
at org.lwjgl.opengl.Display.makeCurrentAndSetSwapInterval(Display.java:1050)
at org.lwjgl.opengl.Display.setParent(Display.java:478)
at amber.TestApplet.startLWJGL(TestApplet.java:43)
at amber.TestApplet$2.addNotify(TestApplet.java:120)
at java.awt.Container.addImpl(Container.java:1068)
at java.awt.Container.add(Container.java:365)
at amber.TestApplet.init(TestApplet.java:129)
... 2 more
Googling for a solution has been useless so far: all the results point to an error involving LWJGL which the game MineCraft encountered at some point in time.
Needless to say, I am very confused and I would greatly appreciate any tidbit of light that could be shed on this beginner issue of mine.
lwjgl has some problems with multi-threading since the openGl library is static.
Judging from this exception:
Quotejava.lang.IllegalStateException: From thread Thread[thread applet-amber.TestApplet,4,file:/a/path/-threadGroup]: Thread[Thread-3,4,] already has the context current
I'd say this is your problem.
Try it without creating a new thread in your code.
I've never really understood the benefits of running your main game loop on anything but the main thread.
That seemed to fix that issue, thanks!