Saturday, December 11, 2010

New release with OpenGL rendering

I'm happy to say that JA2DAPI now has OpenGL as a back end alternative to Java2D. Why is this so exciting? OpenGL is a graphics library (written in C) that allows direct access to graphics hardware via it's infamous rendering pipeline (see the wonderful diagram at www.opengl.org/documentation/specs/version1.1/state.pdf). This means it is very low-level and often times pretty cumbersome. It's not object-oriented and is based on a state machine model. In other words, it's very powerful and efficient, yet not at all user friendly for the recreational game developer.

So, for the latest release, I've added OpenGL rendering, but I've put it completely under the hood so JA2DAPI users don't have to worry about making gl calls. So, you get the awesomeness that OpenGL can provide for 2D developers without all the headache.

Okay, now to the fun stuff. I've added a package called twodapi.lwjgl. This contains a set of classes that should look familiar to you if you know JA2DAPI. There's OpenGL versions of all the base classes as well as the GeneralScroller class (here called ScrollerGL). The class that kicks everything off is the GLPainter. The easiest way to get started is to extend this class:

import twodapi.lwjgl.*;

public class GLStarter extends GLPainter
{
    public GLStarter()
    {

        //super constructor params are window width and height
        super(1024,768);
    }
  
    public void gameInit()
    {
        //Add game initialization code
    }
  
    public void gameUpdate(float interpolation)
    {
        //Called every frame. Add update code.
    }
}


Here, we see the bare bones of a GLPainter extension. In the constructor the super constructor must be called with the window width and height as parameters. The method we have to override to do anything is gameInit(). This is where all game initialization code should go, including initialization of variables and instantiation of classes. The other overridden method is gameUpdate(). This is called every frame update and the float parameter interpolation is the number of seconds since the last frame update. This is where game objects can update their state. An alternative, if implementing SpriteGL or FlipBookSpriteGL classes is to override the update() method to update game state in the same fashion.

So, how is the frame rate determined? LWJGL, the Java OpenGL bindings I've used in JA2API has a VSync feature that syncs renders with the monitor's refresh rate, if VSync is supported by the system's graphics card. This provides the smoothest animation possible and does away with the rendering artifacts you often get with Java2D (such as tearing). If VSync is not support by your graphics card, frame updates occur as often as possible (call the GLPainter's getFPS() method to get the frame rate at a given point). 
 
Here's a simple implementation that displays a background and a spaceship that can be rotated with the left and right arrow keys and moved forward with the up arrow key:

import org.lwjgl.input.Keyboard;
import twodapi.lwjgl.*;

public class GLStarter extends GLPainter
{
    private SpriteGL ship;
    private KeyControlsGL keyControls;

    public GLStarter()
    {
        super(1024,768);
    }

    public void gameInit()
    {
        keyControls = createKeyControls();
        keyControls.set(Keyboard.KEY_LEFT);
        keyControls.set(Keyboard.KEY_RIGHT);
        keyControls.set(Keyboard.KEY_UP);

        setBackground("/images/purple-galaxy-stars.jpg");

        ship = new SpriteGL("/images/ship.gif");
        ship.setLocation(500, 330);
        ship.setScreenWrap(true, this);
        addToPaintList(ship);  
    }

    public void gameUpdate(float interpolation)
    {
        if (keyControls.isPressed(Keyboard.KEY_LEFT)) ship.rotate(-500*interpolation);
        else if (keyControls.isPressed(Keyboard.KEY_RIGHT)) ship.rotate(500*interpolation);
        if (keyControls.isPressed(Keyboard.KEY_UP)) 

            ship.moveRadial(ship.getRotation()-90, 300*interpolation);
    }

    public static void main(String[] args)
    {
        new GLStarter();
    }
}


One thing you may notice is the Keyboard class constants being used for the key controls. These are the LWJGL's keyboard constants and they're pretty straightforward. They're in the form  

Keyboard.KEY_*

where * is the key name.

The second thing you may have noticed is that angles are in degrees here. This is an OpenGL thing and I was too lazy to convert to radians.

The other thing you may have noticed is the multiplication of the movement and rotation amounts by interpolation. This is good practice with OpenGL because the frame rate can vary, especially if your graphics card doesn't support VSync. Think about the amount you multiply by interpolation as the amount you want the sprite to move, rotate, etc in 1 second.

Thanks for reading. I still haven't thoroughly documented the OpenGL features, but the classes and methods are extremely similar to those in the twodapi.core class, so I would recommend looking at the javadocs for the core package if you need help. If they're of no help, feel free to email me at bgsimpkins@gmail.com.

No comments:

Post a Comment