139 lines
No EOL
7.5 KiB
Markdown
139 lines
No EOL
7.5 KiB
Markdown
---
|
|
title: Michael Abrash's Graphics Programming Black Book, Special Edition
|
|
author: Michael Abrash
|
|
date: '1997-07-01'
|
|
isbn: '1576101746'
|
|
publisher: The Coriolis Group
|
|
category: 'Web and Software Development: Game Development,Web and Software Development:
|
|
Graphics and Multimedia Development'
|
|
chapter: '34'
|
|
pages: 648-650
|
|
---
|
|
|
|
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.
|
|
|
|
> 
|
|
> 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. |