![]() Scalar's GP-TRICKS Homepage
A Different Way of BlittingWriting a Sprite CompilerIntroduction The first graphics tool I have ever written, still back on my old CP/M computer, was a vector graphics program that generated BASIC source to directly draw lines, boxes, and circles. Although the graphics that could be done with the program - and with the computer at all - was very simple, this scheme worked amazingly well. There was no need to load a file with single pixels, and the BASIC commands could be executed reasonably fast. And since there was no standard bitmap file format, why invent one if it was disadvantageous? Then came the time of the PC, with well standardized formats and comfortable software. I quickly abandoned self-made graphics tools and resorted to higher quality software. In the old DOS days, PCX seemed to be the format all programs supported, and so it also became my graphics exchange format of choice. Loading a bitmap and blitting it to memory is easy. If no transparency (on pixel basis, of course) is required, it all boils down to copying chunks of memory. And even if pixel transparency is needed, in a palettized graphics mode it's still easy: You just define one of the colors available as being transparent and skip it. Here are some bytes unequal to the transparent color, draw them. Here comes one that is equal to the transparent color, skip it. Here comes another one; and another one. And so on. This gave some smart people something to think. In order to determine if a pixel is to be drawn or not, the program has to compare the pixel's color to the transparent color. In assembler, it looks like this:
Remarkable about this little piece of code, which might well be found in many inner loops, is that even if no pixel is drawn - if nothing is done - the first three instructions will still be executed. "But how should the blitter know that the pixel is transparent before checking it?" you might ask, and you are right. The program can't know, but this situation is still something to complain about. You are wasting cycles. What the program needs, of course, is foresight. And as usual in programming, this foresight has to be built in by the programmer.
Efficiency Considerations This is the beginning of a compiled sprite with dimensions 90 by 60. As you can see, only seven pixels are drawn in the first line, six of them are handled by word transfers. Pretty efficient, huh? Maybe my idea of generating BASIC code wasn't that bad after all. And for most sprites, the results will be similar since non-transparent pixels are consecutive most of the time: In the example above, I had 1263 word transfers and only 207 byte transfers. The downside of compiled sprites, however, are enormous memory requirements. The beforementioned 90 by 60 bitmap takes up 5400 bytes in an 8-bit color mode. The compiled sprite, even though half of the pixels were omitted, consumes 10104 bytes of memory! This is due to the fact that a byte transfer is coded with six bytes and a word transfer with seven. You know what that means if only small parts of the bitmap are transparent... Before we get to talk about writing a sprite compiler, let me mention that you have to consider the advantages and disadvantages of a compiled sprite carefully. A compiled sprite is good for small sprites with a lot of transparency that have to be drawn very often, like a mouse cursor. Big bitmaps, like backdrop screens, don't lend themselves to be compiled. Sprites with no or only little transparency will also love you for being blitted the normal way. And bitmaps that need to be changed during runtime are also sure compilation killers. Although it is possible to compile sprites in runtime using techniques similar to self-modifying code, the hassles and the time required to generate the code usually outweight the benefits.
The program as such does not compile; some functions inside the unit VGALight are required, namely VGAInit and VGADone to initialize and exit the VGA mode 13h, GetPix to read a pixel from screen, Bar to draw a solid bar on screen, and finally LoadPCX to load a PCX file into video memory. If you have trouble getting those functions written, I would happily send you the VGALight library per e-mail.
| |||||||||||||||