PalmOS Iceblox: Technical stuff

In my opinion, Sun made a couple of really boneheaded mistakes when they came up with the KVM specs. Mistakes that make it terribly akwkward (though not impossible) to develop advanced arcade games in Java for PalmOS devices:

  1. There is no official support for transparent pixels.
  2. Although an offscreen graphics buffer exists, there is no way to draw directly on it.
The implications of their first mistake become apparent when you need a background that isn't just a single color and/or you want some of the mobile objects to occasionally overlap in a natural way, as shown to the far left of the sketch below.

But the KVM only allows black-and-white (OK, they're technically black and green, but I'm going to use the expression B&W for simplicity) bitmap objects, with no transparency. That means you will have to settle for defining bitmaps like the ones in the middle, and accept the way their enclosing rectangles mess up the background and other mobile objects (like on the right).

(In theory, there is a way to achieve transparency. From PalmOS 3.5 and on, the operating system itself allows both transparent pixels and greater bit depth, but you need to build your own bitmap encoder and the result will look awful on devices that run earlier versions of PalmOS.)

As for Sun's second mistake, well ... Everyone who has tried to develop at least a moderately advanced arcade game in Java knows the importance of using buffered graphics. Ideally you'd use three buffers, but two are acceptable if you don't mind your mobile objects flickering a bit. The KVM has two graphics buffers and a method for copying pixels between them, but the drawing tools only work on the visible buffer. The offscreen buffer is off-limits to all the drawLine, drawRectangle, drawBitmap, etc.

In other words, you need to draw everything in the visible buffer first and you can't modify graphics data once it has been copied into the offscreen buffer. With one exception: through the copyOffScreenRegion method itself. Rectangular blocks can be copied back and forth or within an offscreen or visible buffer itself. With some clever planning you can sometimes use this feature to both maintain a dynamic offscreen buffer and "fake" transparency. I will now show you how I did this in Iceblox.

On the left is an example screenshot of the visible buffer during play. You can see the penguin and a flame. This situation seems simple enough to handle with just a single graphics buffer -- draw the objects, wait some milliseconds, erase them, move them and repeat. But it becomes tricky when a bonus symbol occasionally overlaps a stationary object (a block of ice). Then erasing it is not just a matter of drawing a black rectangle in its place.

That's why a second buffer is used. You copy its graphics data onto the visible buffer and in a single step you get a clean background you can draw the mobile objects on in their new positions.

On the right is an example of the offscreen buffer I use in Iceblox. Apart from having no mobile objects drawn on it, the main part of it is the same as what the player sees. But the bottom row, I realized, doesn't need to be buffered. It isn't part of the playing field. That meant I could use it as storage space for the parts that make up the background. As you can see, the rightmost four 16x16-pixel partitions are the building blocks of a level: empty, ice, frozen coin, rock. I construct a level by copying those blocks onto the playing field above, and I can easily update it later, when the player moves blocks around or crushes them.

Also important is the left half of the bottom row. On the PalmOS, when working with B&W graphics, black pixels are "ones" and white pixels are "zeroes". By copying a flame in "AND" mode from there to the visible buffer, and then "OR"ing a pair of eyes onto it, I get the same effect as if the flame had had a transparent background. Same thing with the bonus symbols, except that I "XOR" them, to make them stand out better.

I don't do this with the penguin or the moving ice blocks. The penguin is always drawn first, on a black background, so the player will never notice the black rectangle surrounding it. And the blocks are already perfectly rectangular. They don't need transparency.

A few words about the applet

The Java applet that lets you play PalmOS Iceblox in your browser isn't really an emulator. That would be an exaggeration. I prefer calling it a "mock-up" of the PalmOS 3.5. It has a functioning clock and scrollbar, and you can click on the icons, but only the one titled "Iceblox" does anything (yet).

If you compare the start screen of my applet (left) with that of a real Palm device (right), you will notice that it isn't a 100% perfect imitation. A hardcore computer geek would have copied the entire Palm system font, whereas I opted for the easy solution and used the standard 9-point Helvetica of the client computer. They have many similarities, but are far from identical. PalmOS characters have been designed to take up no unnecessary space.

When you click on the Iceblox icon, the mock-up Palm screen displays and activates a bloxCanvas object. This is an implementation of an abstract superclass palmCanvas I built for maximum expandability, in case I want to put in more Palm games later on. palmCanvas contains the font f, the FontMetrics fm, the background color avocado (yeah, but what would you have called it?) and two methods click() and beep() for playing sounds.

If you want to see how the classes fit together, here is the source code palmulator.java.

Ideally I would have liked to keep the application-related classes out of the mock-up applet and only load them at runtime, when the user clicked on the corresponding icon. Alas, for security reasons this can't be done in an applet. All classes have to be downloaded and verified before the applet starts. But at least I can keep the graphics data outside and don't load that until I need it.