April 12, 2012

From Java2D to OpenGL

I started game programming with Java using the default 2D API.
It is easy to use and fast enough for drawing images, which is basically all you need to create a tile based game with some animated sprites.
But the support for creating game eye candy like color effects, lighting, shadows or particles is quite limited. While you have access to every single image pixel, the drawback is a more or less heavy performance loss, emphasis on more, most probably.

Luckily you can use OpenGL with Java.
There are several bindings and frameworks available. I decided to use LibGdx with LWJGL as backend. LibGdx has a good reputation performance wise, and is furthermore based on classes and examples presented in the book "Beginning Android Games" which is also a good and gentle introduction into OpenGL. Then, there is an awesome lighting library available: Box2dLight. That leads to the most important advantage:
Abstraction from OpenGL, which is very low-level, static and stateful. Enough said.

Eventually, with little knowledge about OpenGL, I was able to implement a new renderer based on LibGdx in a few days. Some pitfalls were to overcome, though:

Multithreading is problematic if possible at all. Better do anything OpenGL related in one and only one thread. Loading images, drawing, creating lights, disposing resources. While it shall be possible to activate the OpenGL context in multiple threads, it did not work for me.

The default coordinate system of LibGdx has it origin in the left bottom, which did fit not with the existing game relying on the upper left as the origin. But with configuring a camera that's very easy to overcome, as follows:

OrthographicCamera cam = new OrthographicCamera();
cam.setToOrtho(true);

This y-down camera is then used for drawing sprites and tiles. Additionally, all textures must be flipped vertically. Best to use a TextureRegion for that.

Even if you are using an object abstraction layer on top of OpenGL, you have to keep in mind, that after all, every operation invoked on a Java object ends up in OpenGL which is, well, static and stateful. Thus, there is a lot of dependency and interaction going on under the hood. You can not think and design like it was a real object-oriented system even if certain classes seem to encapsulate OpenGL.

Be sure to adjust the viewport dimension with the camera. I spend some time wondering why I got weired mouse click coordinates. In the end it turned out that the camera was 64 pixels lower than the viewport due a copy-paste-action from my Java2D renderer.You get what you deserve, I guess. It was not visible, OpenGL did a good job in stretching.

The basic and most important classes are: 
  • OrthographicCamera
  • Texture
  • TextureRegion
  • SpriteBatch
  • BitmapFont
SpriteBatch is for drawing all kinds of images, animated sprites, tiles, HUD items and text.

Unfortunately, LibGdx forces you into a predefined application skeleton which I don't need and want to use. That means, access to several configuration classes is restricted, so that I had to put some of my own game classes into a gdx package. It's good to have a standard easy-to-use setup, but it should be an option and not block different valid approaches. But that's only a minor issue.
Good progress so far :)

No comments:

Post a Comment