Fat Zombie!

Some time ago i talked about including Cal3D into libgdx for skeletal animation. It’s said to have an excellent Blender exporter and what not. Unfortunately the format is not straight forward and the library itself relies heavily on the STL. So i was looking around for other simpler skeletal animation formats and found the old MD5 model format by id. This will be the format supported by libgdx for the time being.

I had a little time today to implement a basic loader and debug renderer in Java. Here’s the result so far:

An MD5 model consists of 2 things: the mesh file and a couple of animation files each holding the keyframes expressed as skeletons for each animation like walking, shooting etc. I only implemented loading the mesh file which holds a base skeleton as well as the mesh data itself (which is composed of several meshes). The animation file format is just a couple more skeletons defined. I have already implemented the actual vertex skinning (albeit in Java) and it works as expected. Tomorrow i will try to write the loader for the animation files as well as a better renderer. I currently use ImmediateModeRenderer for the debug rendering which is of course a “little” slow. Fun times! The latest progress is already in SVN along with a test (desktop only for now).

Also: i noticed that libgdx is often refered to as a 2D game development library. I dunno why people got that impression. Libgdx is useable for 2D and 3D games.

  • Share/Bookmark
 

Well, at least in the latest SDK i just downloaded the bindings are still incomplete. As stated in an earlier post the current Java OpenGL ES 2.0 bindings are pretty much useless as they do not support Vertex Buffer Objects. This circumstance was communicated to the Google Android team via the mailing list. Roman Guy confirmed that they will take action on this but up until today with the official Android 2.2 SDK the problem still exists. GLES20.glVertexAttribPointer still only takes a buffer and there’s no overloading of the method offering to specify an integer offset into a previously defined VBO. That is kind of sad as it makes the Java bindings still a second class citizen. With the integration of the trace JIT in 2.2 there is less incentive to work on an NDK level for game programming. In their Google I/O talk on the latest and greatest on Android Google even used Replica Island to demonstrate the performance benefits of the JIT.

All new devices support GLES 2.0 from what i can see and they’ll surely get a nice update to 2.2 soon (my trusty N1 has it already). With the lack of the above mentioned method it is kind of impossible to write high-performance games with GLES 2.0 in pure Java at the moment. This makes me a bit sad as i love the way they try to achieve cross platform compatibility (arm, x86, whatever other platforms might be supported in the future) by using a Java VM like Dalvik.

This will not hurt the “big bad companies” like Gameloft as their games have a C++ code base anyways. It is more of a problem for the hobbyist who does not have the intention to create games for Android, IOS and other platforms and wants to stick to Java. Debugging NDK code is possible but still a pain in the ass.

Oh well /rant

You can still use my OpenGL ES 2.0 wrapper if that helps you :)

  • Share/Bookmark
 

Android OpenGL Benchmarks

Over at Android and me they did a series of OpenGL benchmarks with various second generation devices. Pretty interesting read albeit some of things mentioned like the JIT don’t really contribute to the performance.

The quintessence: the PowerVR in the Droid is still a beast, HTC is a little behind. I would not have included the MyTouch Slide but that’s just me. In any case, all devices are heavily fill-rate bound. Gonna check out some of the benchmarks on my devices. Should be fun to watch.

Oh, and the Samsung Galaxy S just pwns them all.

Obligatory video:

  • Share/Bookmark
 

Froyo OpenGL 2.0 Java Bindings

Oh noes! Google screwed up! Bash, bash, bash :p

As stated by James in a comment on the original custom bindings post i did in march, the new GLES20 class is missing a vital method name glVertexAttribPointer. Well, there is a method called like that but it only takes a buffer meaning that you can use the Java bindings only when you don’t use VBOs. A major pain in the ass as vertex arrays are potentially slow due to constant over-the-bus transfers. You can in the meantime use the JNI wrapper i wrote which is located at http://code.google.com/p/gl2-android/. It’s full featured and i used it for that project i cancled earlier this year, so it’s tested too.

As said in the last post: slap Google!

Update: all is well, Google’s OpenGL guy is looking into it according to Roman Guy over at the developer mailing list. Only problem is that i already have 2.2 on my Nexus One now. So i guess it will not be included in the 2.2 builds that the other manufacturers are working on atm :/

  • Share/Bookmark
 

  • Share/Bookmark
 

I hate Qualcomm, i really do. The mesh class in libgdx is doing everything according to OpenGL best practices and is especially optimized for some nasty Android specific cases. As stated in an earlier post i got 22fps on the hero with a simple SpriteBatch based test. Here’s the code for the render method:

public void render(Application app) 
{	
	GL10 gl = app.getGraphics().getGL10();
	gl.glViewport( 0, 0, app.getGraphics().getWidth(), app.getGraphics().getHeight() );		
	gl.glClear( GL10.GL_COLOR_BUFFER_BIT );
 
	spriteBatch.begin();
	spriteBatch.drawText( font, "fps: " + fps, 0, app.getGraphics().getHeight(), Color.RED );
	spriteBatch.end();
 
        .. fps counter update ...
}

So we clear the screen and then draw a simple fps counter. Now, SpriteBatch works in this way: a Mesh is instanciated with a fixed maximum of vertices it can hold. Each time one of the SpriteBatch.draw/drawText methods are called i first fill a float array with the appropriate data for the quads and then upload them to the mesh which hopefully is a dynamic VBO on the GPU (in some cases it won’t be, e.g. on devices were VBOs are not supported or buggy like on the Behold 2). I of course only upload and render when either the texture changes, SpriteBatch.end() is called or the mesh is completely filled up with quads from previous yet unrendered draw calls. In any case i need to update the VBO with the new vertex data. Any sane programmer using OpenGL would use glBufferSubData in that case as it is specifically designed for updating poritionions of an VBO that is already initiated and for which memory was already allocated. Guess what. Qualcomm screwed that up. That call takes an insanely high amount of time and gets a normally perfect 60fps down to 22fps. Awesome Qualcomm, i applaud you.

Funny extra: the same is true for glSubTexImage2D!

I hope the MSM7200 dies a quick death and that everything is fixed on the Nexus One.

The changes are commited to SVN i will upload a new libgdx version tomorrow.

  • Share/Bookmark
 

libgdx bug on htc hero

I could only test on the emulator and my droid for the past 3 weeks. Today i got my hands on the hero i gave to Stefanie. Well, seems like the GLSurfaceView i used and copied from the latest git version does not work on the Hero (however, it does on all emulator versions from 1.5 to 2.1 upwards). That one i fixed. Now the second question is why SpriteBatch is so extra ordinarily slow on the hero. With a simple test that just draws the fps i get 40 on a 1.5 emulator. On my hero i get 22fps. Wtf? I hate the MSM7200 chips so much i could cry…

Sorry for the inconvenience.

  • Share/Bookmark
 

But it won’t really concern you as the end user. Given the upcoming work Christoph will do i had to split up libgdx into modules. If you are going directly via SVN you will now find 5 projects in there.

  • gdx: This houses the platform agnostic API as well as the native code (which is also platform agnostic, just needs a recompile to get the various shared libs
  • gdx-backends-android: This one contains all the Android specific code
  • gdx-backends-desktop: This contains all the desktop specific code, basically wrapping Jogl among other things
  • gdx-tests: The simple tests i write when implementing a new class or functionality, each test has a main method that wil start a JoglApplication executing that test
  • gdx-tests-android: The android activities starting all the tests in gdx-tests

As an end user you really only care about the API which will always come bundled with all necessary dependencies and shared libs. For people that use the SVN directly you simply have to re-checkout the trunk, all project dependencies are setup automatically.

I’m still not settled on whether to package the API and the backends in a single jar or have three seperate jars, one for the API and one for each of the two backends. The software engineer in me tells me to go for the later option while the lazy ass in me tells me that people will like a single Jar approach better. If you have suggestions leave them in the comment section.

  • Share/Bookmark
 

A warning before we start: this tutorial will not teach you OpenGL ES. There’s a lot of sources out there that do a much better job than i’d be capable of. So let me give you a couple of links before we start.

  • OpenGL from the ground up: an extremely well written tutorial series on OpenGL ES 1.x. Covers all the basics you need to get started with OpenGL. Note that the tutorial is written for the IPhone and uses Objective C/C++. This shouldn’t be a big problem though as the API is the same.
  • OpenGL ES at Khronos: Khronos is the consortium responsible for all the OpenGL APIs out there as well as other things like OpenCL or the Collada format. The page linked includes the specifications for OpenGL ES 1.x as well as 2.0 as well as online manuals. It is a must to read this stuff if you really want a full understanding of what you do.
  • OpenGL ES 2.0 Programming Guide: the definite guide to OpenGL ES 2.0. It is more than worth the money and should be on any OpenGL ES programmer’s book shelf

Do not ever NEVER check out the Nehe tutorial series. It is outdated, does many things completely wrong and boils down to code dumps that don’t really explain anything. If you think you can do graphics programming with just copy & pasting codes, then go ahead and try them. I strongly advice against it. You were warned.

So now that you’ve read and understood all things OpenGL ES let’s look at how you can harness its power with libgdx. The first thing you will do is to create an instance of Application, either a JoglApplication or an AndroidApplication. In either case you must specify if you want to work with OpenGL ES 1.x or 2.0. The problem is that the two versions are incompatible so you have to decide what you want to use. This does not mean that you can’t write a game that has a rendering path for OpenGL ES 1.x and a second path for OpenGL ES 2.0. If you have an OpenGL ES 2.0 rendering path that you want to use you have to tell the Jogl and Android application to initialize a compatible surface and context. Here’s how you do that with the JoglApplication:

public static void main( String[] argv )
{
   JoglApplication app = new JoglApplication( "My app", 480, 320, true );
   ... funky stuff ...
}

The last parameter of the constructor tells the JoglApplication to setup an OpenGL ES 2.0 context if available. On Android you do something similar:

public class MyApp extends AndroidApplication
{
   public void onCreate( Bundle bundle )
   {
      super.onCreate( bundle );
      initialize( true );
      ... funky stuff ...
   }
}

Here we have the method AndroidApplication.initialize() which has a single parameter specifying whether to use OpenGL ES 2.0 if available.

To check whether OpenGL ES 2.0 could be initialized you do the same in both scenarios. You ask the Graphics instance whether OpenGL ES 2.0 is available or not:

if( app.getGraphics().isGL20Available() )
   app.log( "my app", "yay, we can do shaders!" );

If this returns false you have to fallback to OpenGL ES 1.1 or even 1.0. To determine which 1.x version is available you use similar methods:

if( app.getGraphics().isGL11Available() )
   app.log( "my app", "yay, we can use vertex buffer objects" )
if( app.getGraphics().isGL10Available() )
   app.log( "my app", "oh crap, stone age time" );

OpenGL ES 1.1 is backward compatible with OpenGL 1.0, so if 1.1 is available so will 1.0. NOTE: if OpenGL ES 2.0 is available neither OpenGL ES 1.1 nor 1.0 will be available and vice versa as 1.x and 2.0 are not compatible!

So we now know how to initialize an application with OpenGL ES 2.0 support and how to check whether that was successful. The next thing to get going is to get a hold of the actual OpenGL API. On the desktop you’d normally use things like Jogl or LWJGL in Java, on Android you get an instance of GL10 or GL11 passed to your Renderer.onDrawFrame() method. Note that there’s no Java OpenGL ES 2.0 support on Android yet! Another thing to note is that desktop OpenGL is quiet a bit different to OpenGL ES. OpenGL ES is a streamlined version of desktop OpenGL with a lot of unnecessary features removed. It also adds functionality, the possibility to use fixed point math instead of floats being the most prominent one.

Now, with libgdx i want to offer a cross-plattform way to develop and prototype your games on the desktop and deploy them on Android without changing any code. This means that with respect to OpenGL we have to go for the least common denominator which is OpenGL ES. This is of course a problem as a couple of the OpenGL ES features are not available on the desktop. I therefor wrote a wrapper around Jogl implementing the OpenGL ES API (yes i’m that crazy…). It even supports fixed point, except for vertex buffer objects. The feature is working but i’d advice against using it. In my benchmarks i couldn’t find significant benefits from using fixed point on my Android devices (HTC Hero, Motorola Droid). On newer devices fixed point will make even less sense as they will most probably sport proper FPUs. The Droid already has an FPU.

Ok, we still have no idea how to get our hands on the OpenGL ES API. Here’s how that works:

GL10 gl = app.getGraphics().getGL10();
GL11 gl = app.getGraphics().getGL11();
GL20 gl = app.getGraphics().getGL20();

Note again: when OpenGL ES 2.0 is available then Graphics.getGL10() and Graphics.getGL11() will return null and vice versa. If OpenGL ES 1.1 is available then you can either get a GL10 or a GL11 interface. If only OpenGL ES 1.0 is available you can only get a GL10 interface.

The interface GL10, GL11 and GL20 implement the full OpenGL ES specifications. The Java bindings for OpenGL ES 2.0 where done by my and can be downloaded seperately if you want from http://code.google.com/p/gl2-android/. It’s a tiny JNI bridge to the native OpenGL ES API.

Once you get a hold of a GL interface instance you can store it somewhere instead of always querying the Graphics instance. It will stay valid over the complete life cycle of the application.

All that is left is to use the GL instance in your rendering method, maybe like this:

public void render( Application app )
{
   GL11 gl = app.getGraphics().getGL11();
   gl.glClearColor( 1, 0, 0, 1 );
   gl.glClear( GL11.GL_COLOR_BUFFER_BIT );
}

That should be more than enough to get you started. As stated in the introduction, read all the material about OpenGL ES you can get a hold off and experiment with it. Next time we will have a look at the rest of the graphics related classes that will hopefully make you forget about OpenGL :)

  • Share/Bookmark
 

Most people will not have noticed but there’s a nasty bug in libgdx 0.3 which will wrack havok with indexed geometry that’s rendered via VBOs. If you specify an offset into the indices array when using Mesh.render() the offset was not converted to bytes as is needed with glDrawElements which did some funny things. I commited the change to SVN and will release an updated version some time later this weekend.

That’s why you should always code at night, drunk!

  • Share/Bookmark