Thursday, July 11, 2013

CannonBall in a Web Browser? (Updated!)

I've started converted CannonBall to Javascript so that it will run straight from a web browser with no plugins. I wanted to do this for a number of reasons:

  • It saves porting and means CannonBall will run on any every platform with a modern browser (e.g. tablets, phones etc.)
  • It's a good opportunity to show that CannonBall is pretty fast (some people doubt this). 
  • It will be pretty cool when LayOut is finished to be able to play a customised level by simply clicking a link. No download or messing around with files. 
  • It's interesting to me from a technical/tinkering perspective.
This might not be as painful as it sounds. I'm using emscripten which can convert C++ code to Javascript. (Technically it converts LLVM bitcode to Javascript, but you get the idea). And just to be clear, this version isn't intended to replace the downloadable CannonBall :)

So far, progress isn't particularly exciting to observe:

But actually this is more promising than it may appear. The entire codebase compiles and begins to run. It's simply stumbling on finding the roms as I need to package them with emscripten's file system

So far the process I've followed to get things running was as follows:

1/ Followed the tutorial here for the Windows setup. 

I failed to get everything working from within Visual Studio 2010. Suspect this is an issue with a 32-bit VS 2010 process trying to spawn a 64-bit process as part of the toolchain. But actually fixing this issue proved problematic as I couldn't get clang to compile under Windows, so was unable to compile a 32-bit version to test this theory.

From reading some forum posts, it appears that using Windows 8 would probably solve this issue and the prebuilt clang would work.

2/ Switched to using a Unix/MinGW approach. Plugged the following platform file into CMake.  Ran mingw32-make; prior to this point the makefiles are butchered by CMake to work with Clang and emscripten instead of MinGW. 

3/ Created a customized emscripten.cmake file, which essentially doesn't do very much. 

4/ Fixed the three million compiler warnings reported by clang. It's a more fussy compiler than VS or GCC. I also removed the dependency on the boost library for now to speed up getting something working. 

5/ Converted the bytecode to a html page with embedded javascript using:
emcc cannonball.bc -o cannonball.html

6/ Loaded the file into a web browser. It fails in the way we would expect and spits out some sensible output about the roms. Hurrah!

Overall, it's only taken a couple of evenings to get this far. And most of this time was spent messing around installing stuff, and failing to get things working in Visual Studio. Once I hit upon the right approach, things went relatively smoothly. 

I'll carry on coding over the next few days. As Emscripten supports SDL libraries out of the box, it shouldn't be too tricky to get something working. But let's see... 

Edit: Couldn't resist implementing the file system before bed to see what happened. It kind of runs. But obviously not very well as there's a bunch of stuff I need to do like replace the main loop. Not sure on the colours for now, but probably an easy fix.

14th July: I fixed the colours, and it is now running and playable:

Unfortunately, it's using the software renderer for now. The OpenGL renderer would need a rewrite to make it WebGL compatible. It doesn't just work out of the box. 

The speed is reasonable at 30fps currently, although a little choppy in places. I'm not sure what kind of improvement I could expect if I rewrote the renderer...

If anyone is desperate to work on this further, I can check my work into git for them to mess around with. I may work further on this in the short-term or I may switch back to LayOut again!

I also tested on my Samsung Galaxy S3 phone. It runs pretty well on the Firefox Beta browser (maybe at around 20fps). There's no way to actually control the game though! It runs like a dog on Chrome.

15th July: I realised that using the emscripten_set_main_loop was causing the performance problems. Rewrote the main loop, so that the frame timing is done in pure JavaScript, with a call to the external C++ tick function. This is a similar approach to the port of Snes9x.

The results are outstanding. Unthrottled, the engine runs in widescreen at 80fps in Firefox on my desktop PC.

On my Samsung Galaxy S3, the engine now runs at a solid 30 fps in the Firefox browser (I haven't tried it unthrottled yet). Given that most elements of the game only update at 30fps in the original arcade game, this means you can run OutRun at full-speed. Pretty impressive for Javascript running in a phone's web browser!

24th July: After some experimentation, I now have relatively solid audio working on the PC. Unfortunately, directly porting the SDL audio code didn't lead to good results. Instead I replaced the SDL code with custom Javascript using the WebAudio API and an interface into the C++ code.

The results are decent on a fast enough PC with Chrome or Firefox Nightly.



tailor-made for Firefox OS devices!

Adrian Smethurst said...