by Digby » Sep 14, 2001 @ 11:23am
The majority of my Pocket PC programming centers around performance tuning. Faster ways to perform alpha-blending, move sprites around, mix audio, and rasterize triangles. Frequently in writing high performance graphics routines we will sacrifice image quality in the name of raw speed. <br><br>Most of the time this speed vs. quality tradeoff is worth it because the images are updated several times per second and as long as objects are flying past you and you're concentrating on hitting them with some weapon of destruction you can get away with it. However, if your game has a static background or if the player in your 3D game takes time to look around in the scene things that didn't look so bad when moving start to look a bit crufty.<br><br>Lately I've been thinking more about what to do with this with code running on my iPaq. The iPaq is even worse as it only has a 12 bit (444) display. Banding artifacts begin to show up in images that contain smooth gradients of color. This is a direct result of not having enough color resolution to correctly draw the gradient. This problem isn't specific to the iPaq (as I'll show later) as even the devices with 16 bit per pixel displays can still exhibit the banding problem with a finely gradiated image. The bands will be smaller, but they are still present and visible.<br><br>A popular method to combat this lack of color depth resolution is dithering. Dithering is a technique used to extend the color resolution at the expense of spatial resolution. Instead of using a single 12 bit pixel (iPaq), you can use multiple pixels and alter the values slightly to trick the eye into summing the surrounding pixels into seeing an intermediate color value that couldn't be represented by a 12 bit value. This tecnique was first used in printing gray-scale images on black & white (1-bpp) printers.<br><br>There are a number of dithering techniques. Two of the most popular are ordered-dither and error-diffusion. The technique that I've been playing around with is ordered-dither. It provides acceptable results and is faster than the other methods that I've tried. It has an added advantage in that you can work with a single pixel at a time and you don't need to read or write to surrounding pixels while working with that pixel (error-diffusion has this limitation).<br><br>I don't have time to go into ordered-dither algoritms here, but I'd like to share my results with you. I've saved all these images as 256x256 uncompressed bmp files, so that any compression effects wouldn't taint the images. I've also creating versions of the images as they would look being displayed on an iPaq (12-bpp) and a Casio/HP (16-bpp). You can load the original 24-bpp source image on your Pocket PC and it should look the same. Also, you should view these images in MS Paint rather than your web browser. The reason is that IE (and maybe others) will dither images itself and that will taint the original image.<br><br> source image is a linear gradient fill from white to black. The image is 256 lines tall, so each line is a different color value (24-bpp = 256 gray shades). It looks pretty good on a 24-bpp display.<br><br>If you display that image on your 16-bpp device, it will look like . If you look closely, you'll begin to see banding in the form of horizontal stripes. This is because there are more lines in the image (256) than there are levels of gray (32). Note: some devices that use 565 displays can toggle the green component and get 64 levels of gray, but the bands should still show up.<br><br> next image is the original gradient bitmap, saved in the equivalent of a 12-bpp image. This is what you would see on an iPaq if you viewed the original 24-bpp gradient bitmap. Pretty ugly. The bands are 16 pixels high and quite obvious.<br><br>OK, is the original image that has been dithered for a 12-bpp display. I think it looks pretty good. If you zoom in on the image you can see the signature pattern of an ordered-dither. I mentioned before that I wasn't going to go into the algorithm here, but it's basically 2 ANDs, 1 table lookup, and adding the value from the table to each color component (clamped to 255). <br><br>This will help you get started understanding the process of dithering and explains ordered-dither and error-diffusion. I'm happy to e-mail the code for the dither routine I used to generate the above image to all who request it.<br><br>One other thing worth mentioning is that the DSTN displays found in Pocket PC devices frequently have dithering implemented in hardware. This is usually done to combat a further lack of color resolution in the actual display. Some of these displays are actually 3-3-3 and then claim to be 4-4-4 or 5-5-5 by dithering. The reason I mention this is that in theory if you're dithering the image it can interfere with the dither in the display and can make your image wiggle as it's scrolled or repositioned on the display. I have yet to see this on my iPaq, but I thought I'd make you aware of it.<br><br><br>