Sunday, January 13, 2008

Weekend project: porting a game to QVGA

Following a mediaplayer, games would be next thing people ask for Angstrom. So, I decided to look what would be good candidates to add to feed. There're bunch of different games' recipes in OE, but I was thinking about some catchy, dynamic arcade. Of course, SuperTux came to mind! ;-)

OE already has recipe for SuperTux, and quick try in QEMU showed it works. In VGA mode. Attempt to run with QVGA screen resulted only in error that suitable video mode cannot be found. So, I decided to see if quick hack could solve this, and then document what it would take to do so.

Quick look at the source code showed that it is one of the critical cases of software engineering - 640x480 resolution is deadly hardcoded, with numeric coordinates spread around the code. Fortunately, short after I spent 10 mins figuring where to stuff divisions by 2, I googled for "supertux qvga". Hits followed! SuperTux was ported to GP2X and even to WinCE. I took GP2X version to look at.

GP2X port is nice produce of folks who have motivation to do something, but don't know what the diff is ;-). It was also done against SuperTux 0.1.3, while OE had 0.1.2. On the way, I bumped OE's version to 0.1.3 too, while finding that fixed-point patch for 0.1.2 no longer applies to 0.1.3 (will need to rediff). Finally, making diff out of GP2X version and cutting off changes related to autoconf-generated files, I got ~70K patch implementing --enable-320x240 and --enable-gp2x options (adding those was neat, unlike not producing a diff). Applying that patch on top of pristine 0.1.3 (with bitbake recipe of course!) and cleaning off some sloppy gp2x changes which were compiled in even though --enable-gp2x was not given, I finally got the package built. Quickly checking that it doesn't work in 240x320 mode, I had it run with xrandr applied, just to see garbaged fonts and graphics. Of course! Of course gp2x patch doesn't resize the original graphics on the fly, but expects it to be downscaled already, even though such gfx is not included in source archive. I pulled it from binary package though, and few minutes later saw the expected fun:

So, thank you scachi (Ingo Arndt) for doing all the fun work, and leaving dirty work of cleaning it all up to me! ;-D

On that route I proceeded, and next task was figuring out what to do with graphics. Having a binary drop of graphics was for sure no more acceptable than a complete source archive instead of diff. We talk port here, not something. I still don't target that at upstream, but not because it's not worth being there, but because it would be hard to explain what's it all about to people who write draw(537, 39) ;-(. Nonetheless, QVGA graphics must be produced from upstream version during build time. Just few days before I heard pH5 talking about imagemagick-native, so having checked it was not in OE (while target version was), I caught him on IRC to find out that it belongs to "would be nice to have" category. 15mins later it was there, fortunately "inherit native" was all needed for it.

My initial attempts at resizing original SuperTux graphics at 50% proved to give rather bad results, having size as big as original, or even bigger, and for sure much bigger than gp2x versions. But man'ing thru and recalling my old ImageMagick experience quickly gave its fruit by applying adequate color quantization after resize (I used --colors 64). Adding pngcrush-native and running magick's images thru it was final touch - in the end, I got image set ~30% smaller than gp2x's, while still looking better!

What's next? Too big a package. It would be nice to let people install this thing to flash, plus I target it for inclusion in LiveRamdisks, so 6.5Mb compressed package was not very bright. Glancing over data files shipped with SuperTux, it turned that music/ is nice candidate for slimming. First of all, there're few duplicate tunes, just one copy with "fast" suffix. Size was same, and diffing them, there were handful byte changed. Looking thru code, "fast" version is played when level's time limit is running out. I llluv that feature! But not at the expense of my flash ;-I. "fast" version went to /dev/null for the QVGA, and now, small-size version. Secondly, there was a credit.ogg file, which gp2x port replaced with some .xm. Trying .ogg still, I found that SDL can't scroll screen and play 160kbit ogg at the same time, on PXA 400MHz. So, bye, .ogg, good riddance! And thanks gp2x again for offering a replacement.

Now I finally decided to run game on full-fledged hardware - h4000, as earlier I ran it in QEMU and on h3900, which lacks audio. It immediately crashed on startup, complaining about not being bale to load a .mod music. A check of source, then libsdl-mixer recipe and - the latter has mikmod support disabled. Poor. With it on, I finally have a nice, commercial-grade arcade running on a Linux PDA! I even was able to quickly finish couple of levels, even though controlling PDA in a landscape position is not ideal.

Final touch I made was extracting bonus levels to separate packages. Level description are text files, taking more than a megabyte in raw size, but packages turned out to be ~50K. Well, let's save space for ext2 people nonetheless, and most importantly, have a complete experience of what it takes to produce a nice PDA port of a game.

So, that's how it was. I took time to write this long, if not detailed, description, in the hope that it will both motivate people to port games to OE/Angstrom, and will give hints how to do that. So, let's hope that people will care for their favorite OpenSource games, or choose to have such a weekend fun ;-). Otherwise, thinking about it, games are likely the best candidates for bounty-sponsored porting - after all, due to the manner many games are written, it's not too easy to port them to a lower resolution/smaller size/more CPU efficiency. So, if people want more fun, they should take the fun of doing a port (it's much more fun than playing a game itself, trust me ;-D ), or motivate other people who want to do that ;-).

Oh, and back to tux the super: the supertux-qvga recipe should land soon in OE. I hope to dump packages to unstable feed too. Then, there're following TODOs before it's perfect:
  1. Forward-port fixed-point patch to 0.1.3 (I get ~25fps with sound, and that's not too much, and there's jerky scrolling sometimes).
  2. There're few relatively big .mod's which are used relatively rarely. It would be nice to leave just a couple of smaller ones in a core package, to really slim it down, and put the rest in extra-music package.
  3. Fully clean up gp2x patch, it's still too dirty.

No comments: