Previous Table of Contents Next

The big question is, How does Listing 34.1 cycle colors? Via the BIOS or directly? With interrupts enabled or disabled? Et cetera?

However you like, actually. Four equates at the top of Listing 34.1 select the sort of color cycling performed; by changing these equates and CYCLE_SIZE, you can get a feel for how well various approaches to color cycling work with whatever combination of computer system and VGA you care to test.

The USE_BIOS equate is simple. Set USE_BIOS to 1 to load the DAC through the block-load-DAC BIOS function, or to 0 to load the DAC directly with OUTs.

If USE_BIOS is 1, the only other equate of interest is WAIT_VSYNC. If WAIT_VSYNC is 1, the program waits for the leading edge of vertical sync before loading the DAC; if WAIT_VSYNC is 0, the program doesn’t wait before loading. The effect of setting or not setting WAIT_VSYNC depends on whether the BIOS of the VGA the program is running on waits for vertical sync before loading the DAC. You may end up with a double wait, causing color cycling to proceed at half speed, you may end up with no wait at all, causing cycling to occur far too rapidly (and almost certainly with hideous on-screen effects), or you may actually end up cycling at the proper one-cycle-per-frame rate.

If USE_BIOS is 0, WAIT_VSYNC still applies. However, you will always want to set WAIT_VSYNC to 1 when USE_BIOS is 0; otherwise, cycling will occur much too fast, and a good deal of continuous on-screen garbage is likely to make itself evident as the program loads the DAC non-stop.

If USE_BIOS is 0, GUARD_AGAINST_INTS determines whether the possibility of the DAC loading process being interrupted is guarded against by disabling interrupts and setting the write index once for every location loaded and whether the DAC’s autoincrementing feature is relied upon or not.

If GUARD_AGAINST_INTS is 1, the following sequence is followed for the loading of each DAC location in turn: Interrupts are disabled, the DAC Write Index register is set appropriately, the RGB triplet for the location is written to the DAC Data register, and interrupts are enabled. This is the slow but safe approach described earlier.

Matters get still more interesting if GUARD_AGAINST_INTS is 0. In that case, if NOT_8088 is 0, then an autoincrementing load is performed in a straightforward fashion; the DAC Write Index register is set to the index of the first location to load and the RGB triplet is sent to the DAC by way of three LODSB/OUT DX,AL pairs, with LOOP repeating the process for each of the locations in turn.

If, however, NOT_8088 is 1, indicating that the processor is a 286 or better (perhaps AT_LEAST_286 would have been a better name), then after the initial DAC Write Index value is set, all 768 DAC locations are loaded with a single REP OUTSB. This is clearly the fastest approach, but it runs the risk, albeit remote, that the loading sequence will be interrupted and the DAC registers will become garbled.

My own experience with Listing 34.1 indicates that it is sometimes possible to load all 256 locations cleanly but sometimes it is not; it all depends on the processor, the bus speed, the VGA, and the DAC, as well as whether autoincrementation and REP OUTSB are used. I’m not going to bother to report how many DAC locations I could successfully load with each of the various approaches, for the simple reason that I don’t have enough data points to make reliable suggestions, and I don’t want you acting on my comments and running into trouble down the pike. You now have a versatile tool with which to probe the limitations of various DAC-loading approaches; use it to perform your own tests on a sampling of the slowest hardware configurations you expect your programs to run on, then leave a generous safety margin.

One thing’s for sure, though—you’re not going to be able to cycle all 256 DAC locations cleanly once per frame on a reliable basis across the current generation of PCs. That’s why I said at the outset that brute force isn’t appropriate to the task of color cycling. That doesn’t mean that color cycling can’t be used, just that subtler approaches must be employed. Let’s look at some of those alternatives.

Color Cycling Approaches that Work

First of all, I’d like to point out that when color cycling does work, it’s a thing of beauty. Assemble Listing 34.1 so that it doesn’t use the BIOS to load the DAC, doesn’t guard against interrupts, and uses 286-specific instructions if your computer supports them. Then tinker with CYCLE_SIZE until the color cycling is perfectly clean on your computer. Color cycling looks stunningly smooth, doesn’t it? And this is crude color cycling, working with the default color set; switch over to a color set that gradually works its way through various hues and saturations, and you could get something that looks for all the world like true-color animation (albeit working with a small subset of the full spectrum at any one time).

Given that, how can we take advantage of color cycling within the limitations of loading the DAC? The simplest approach, and my personal favorite, is that of cycling a portion of the DAC while using the rest of the DAC locations for other, non-cycling purposes. For example, you might allocate 32 DAC locations to the aforementioned sunset, reserve 160 additional locations for use in drawing a static mountain scene, and employ the remaining 64 locations to draw images of planes, cars, and the like in the foreground. The 32 sunset colors could be cycled cleanly, and the other 224 colors would remain the same throughout the program, or would change only occasionally.

That suggests a second possibility: If you have several different color sets to be cycled, interleave the loading so that only one color set is cycled per frame. Suppose you are animating a night scene, with stars twinkling in the background, meteors streaking across the sky, and a spaceship moving across the screen with its jets flaring. One way to produce most of the necessary effects with little effort would be to draw the stars in several attributes and then cycle the colors for those attributes, draw the meteor paths in successive attributes, one for each pixel, and then cycle the colors for those attributes, and do much the same for the jets. The only remaining task would be to animate the spaceship across the screen, which is not a particularly difficult task.

The key to getting all the color cycling to work in the above example, however, would be to assign each color cycling task a different part of the DAC, with each part cycled independently as needed. If, as is likely, the total number of DAC locations cycled proved to be too great to manage in one frame, you could simply cycle the colors of the stars after one frame, the colors of the meteors after the next, and the colors of the jets after yet another frame, then back around to cycling the colors of the stars. By splitting up the DAC in this manner and interleaving the cycling tasks, you can perform a great deal of seemingly complex color animation without loading very much of the DAC during any one frame.

Previous Table of Contents Next

Graphics Programming Black Book © 2001 Michael Abrash