Thursday, April 1, 2010

GwtQuake: Taking the Web to the Next Level

Back in November of 2009, Joel Webber and I were at a GWT Summit focused on improving the Web and UI latency. Someone was giving a presentation on WebGL, and I saw Joel sitting in the back of the room looking seriously distracted. When I approached him, he said "Did you see this?" and swung his notebook around to show Jake2 -- Quake2 ported to Java running as a Java WebStart Application. I had seen this project years ago, but never knew it had gotten this far.

Right then and there, I knew what he was thinking, I almost didn't need to ask -- he was suggesting that we port Jake2 to the Web using GWT!


The Path to the Web


The idea that you could use GWT to compile something like Jake2 to Javascript seems straightforward, since GWT after all, compiles Java to Javascript, however there is still a lot of work massaging the code to compile, as well as mapping I/O to the appropriate Web APIs.

As you may know, GWT only implements a subset of the Java JRE, and Jake2 relies on many Java classes that GWT just doesn't have:

  • The LWJGL library for 3D

  • and java.nio.Buffer classes

  • java.net.* for networking

  • AWT for keyboard stuff

  • File system APIs for loading data

  • OpenAL for audio



More importantly, it relies on a synchronous API paradigm for doing I/O, and as we know, Javascript is built around event driven I/O.

Mapping I/O


Joel reorganized Jake2 I/O system around event driven pumping to load files. The first thing we did was get the level and model files loading, and rendering using a 2D <canvas> wireframe renderer (no WebGL). After that, Stefan Haustein contributed new JRE classes to implement Java NIO Buffers around WebGL's new typed javascript arrays, as well as a GL renderer based around WebGL.

Joel amazingly got multiplayer up and running on WebSockets and we had great fun play testing deathmatches between Atlanta, Mountain View, and even Sydney.

I went ahead and converted all of the sound to MP3 and implemented an initial sound renderer just by using the DOM Audio element. Later, I refactored the OpenAL code into a base class and provided an implementation of the OpenAL Inverse Distance Clamped sound model that adjusted volume gain of sounds based on 3D position, still, using nothing more than the audio.volume property.

Stefan added an implementation of RandomAccessFile based on LocalStorage to save game files, and an implementation of video playback using the <video> tag.

Most of the work was completed by January by part time contributions, but has been tweaked since then. Stefan, for example, went ahead and ported the entire single player game (no server needed) as static content.

A more detailed post-mortem will be presented during one of my Google I/O sessions, be sure to attend!

Is it slow?


I thought it would be, honestly, I never thought we would get this far, but it turns out that playable framerates are achievable. On WebKit/Chrome I can get 20-25fps on a MacBook, and on my Mac Pro desktop, I get about 45fps. Joel reports that a Linux notebook gets up to 60fps.

What this means for the Web


For years, people have assumed the browser was a poor platform for this kind of thing, and that you'd need something like Flash, Silverlight, JavaFX, or native code. While it is true that you should not expect the browser to rival triple-A titles like Far Cry or Call of Duty in the browser, there is no reason why lots of casual games that used to be implemented in Flash, or are now implemented in Objective-C on the iPhone/iPad can't be done using similar techniques we've used.

Moreover, because it's the Web, all you need to do to invite someone to your game, to share it, is to send a link. You could Tweet a link directly to your game, which when clicked, would make someone join the game in progress. No installs necessary. While this can be done in Flash, it just feels "natural" when it's in the browser.

I hope that this port encourages some people to become even bolder and crazier in the types of Web Apps they're trying to build, because if Quake2 is possible in Javascript using browser APIs, then even more amazing applications are waiting for you to develop, so get started!

The source code for our port is at: http://code.google.com/p/quake2-gwt-port

-Ray