Pages

Tuesday, 13 May 2014

Android OpenGL 2D Skeleton app

When I first started working on Blob Wars : Attrition, I was working Android's canvas view. However, I soon found that this wasn't up to the task; it was far too slow. I therefore decided to investigate switching to OpenGL. This has given a lot of people grief in the past, but after a lot of investigation, I managed to get it working to my satisfaction - i.e: 2d ortho mode, with the y coordinate being at the top of the screen.

I thought I would share the code for this, to help others along the way. At the bottom of this page, you can find a link to both an APK and the source code for this app. You can use it for a template for your own apps, as you desire. However, you MUST credit me (Stephen J Sweeney).

The app will basically fling 400 OpenGL rectangles around the screen, and print the frames per second. It might not sound like anything special, but it will prove a big help for anyone looking for a template to get started. On my Galaxy S3, this app runs at 60fps.

We'll start with the Rectangle class, which will do the main work for pushing the vertex and coord data to the GPU. This class might look complex, but it's rather simple. I won't go into the whole vertex alignment stuff, mostly because I've forgotten. It works, and that's what matters to me.

The class takes either a Texture class (see later) or can be constructed by supplying the width and height. The later is useful if you're simply drawing a square, such as a status bar. The set() and setCoords() methods can be used to change the rectangle's size and texture coords, useful when performing operations such as drawing text.

Two of the most important methods in this class are the begin() and end() calls, which start all the drawing operations. Technically, we don't have to put these here; we could quite easily most them some place else. They're here just to keep things tidy and keep related functionality together.

That's it. It's a bean holding the width, height and OpenGL texture pointer int. Nothing special. We feed this into the Rectangle class. Now that we've got those two classes set up, we can look at loading some textures:

Again, what's going on here should be quite obvious. This class provides some static methods that take either a Bitmap or an InputStream and creates a texture. A couple of notes - we set GL_CLAMP_TO_EDGE to prevent artefacts from showing at the edges of our textures when they're displayed. We also store the texture id in a static array. We do this so that we can delete them when we're done with them (using free()). While the Android OS will delete textures itself when the app finishes, we might want to delete them ourselves at certain points.

OpenGLView sets up our renderer. We target a screen size of 480x800, and grab the screen resolution of the device we're running on, so that we can scale thing later. If we don't do this, then we could send up with a small portion on the screen being used on some devices, or the display being too large on others.

Now we come to the big one - GLRenderer, where all the work is done. Again, but class might look complex, but it's very straightforward.

In the constructor, we create 400 entities, 9 rectangles (to hold the sprites), and grab the scale of the display for later scaling.

onSurfaceChanged() is where we set up our ortho mode, and where we load the textures that we wish to use. We then randomly set a rectangle (with a texture) to each of our entities.

onDrawFrame() is where all the grunt work is done. We first move our entities (do the logic), and then prepare to draw. After calling glLoadIdentity() we set the glScale to get the appropriate ratios. We then call Rectangle.begin() to start the drawing process, and loop through all our entities, calling draw on each of the entity's rectangles. Finally, we calculate and print the frames per second.

That should be enough to get most people up and running. You can download the source code below, as well as an APK that can be run on your device.