abrash-black-book/34-04.md
2013-12-30 20:26:41 +11:00

118 lines
8.6 KiB
Markdown

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 **OUT**s.
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 {#Heading8}
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.
------------------- -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
![](images/i.jpg) *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.*
------------------- -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------