## A Graphics Trick

A Fragment of Code
When I started at Atari back in 1979, they had a little test they used to challenge programmer candidates. They showed them this little fragment of 6502 code:

LDA FIRST
EOR SECOND
AND CONTROL
EOR SECOND
STA OUTPUT

Then they would ask the candidate what the code does. It seems that only the best programmers could figure it out. I don’t rightly recall whether I passed the test, but I do remember that code, because it is one of the sneakiest bits of code I have ever encountered. What it does is to build up a byte out of bits from both FIRST and SECOND, using CONTROL to pick the bits. That is, if bit #3 in CONTROL is a 1, then the value of bit #3 in OUTPUT will be equal to the value of bit #3 in FIRST. If bit #3 in CONTROL is a 0, then the value of bit #3 in OUTPUT will be equal to the value of bit #3 in SECOND. Thus, if CONTROL = 0, then OUTPUT = SECOND, and if CONTROL = \$FF, then OUTPUT = FIRST. But these are uninteresting cases. The interesting case is when CONTROL is some value between 0 and \$FF, in which case OUTPUT is a function of both FIRST and SECOND.

What’s it for?
At this point, you may be wondering, what is the point of this truly obscure fragment of code? I may not be the world’s greatest programmer, but I instantly grasped the significance of this code fragment. This is graphics manipulation code par excellance. This code permits magical things to happen on a computer screen. It enables you to mix two images on a screen in a variety of ways controlled by the complexity of the CONTROL parameter.

Here’s a simple example: suppose that you want to do a horizontal wipe from one screen to another. (A wipe replaces one image with another in an animated sequence that takes about a second. The new image wipes over the old one along a moving front.) The conventional approach would involve writing selected bits in the screen bitmap. (For the purposes of this article, I shall assume simple black and white displays. To extend these concepts to color displays, add bit depth to the examples.)

The basic algorithm
To explain the concept, I shall ask you to imagine three data structures. The first is the original bitmap on the screen, which I shall call FIRST. The second is the new bitmap that we intend to replace it with, which I shall call SECOND. The third bitmap is the control bitmap, which I shall call CONTROL.

The basic algorithm consists of two nested loops. The inner loop calculates a single screen; the outer loop handles all the screens in the complete wipe. The inner loop executes our magic little code fragment on each of the three corresponding bytes from FIRST, SECOND, and CONTROL. It then sends the resulting byte to the screen. This loop does this for all the bytes on the screen.

The outer loop manipulates only the values in the CONTROL bitmap. We first set the bits on one edge of CONTROL to 0’s. Then we set more bits in CONTROL to 0 and repeat the process until CONTROL is all 0’s.

Hotshot programmers will immediately dismiss this technique as impermissibly slow. After all, why waste cycles moving bytes that don’t change? You only need to change the bytes in a vertical column, so why go to all this trouble?

Extensions
Ah, but there’s so much more! You want to do a diagonal wipe? Just change the way you modify CONTROL. The inner loop remains the same. You want a more complex wipe? No problem! Anything you can draw into CONTROL can be the basis of your wipe. For example, suppose that you want a radial wipe. Start with CONTROL being all black, then, in the outer loop, paint a small filled white circle into it. With each iteration of the outer loop, paint a larger filled white circle into CONTROL. Continue the process until the screen is completely white.

This basic approach can be used with ANY geometry. You can create a huge number of wipes, and they don’t have to be specially designed and coded. All you modify is the outer drawing loop into CONTROL; the inner loop remains the same.

Dissolves
But there are other possibilities. One of my favorites is the dissolve. A dissolve fades one image into the other. In a wipe, the new image starts in a small portion of the screen and expands to fill the screen; in a dissolve, the entire image slowly emerges over the entire screen.

To execute a dissolve, you simply start with a CONTROL bitmap that is all 1s, and then start populating it with random 0’s. You can use different patterns for populating with 0’s to achieve different styles of dissolve. For example, you can use a simple procedure in which you repeatedly AND random numbers into CONTROL to get a clean dissolve. I found that it looks better if you replace each CONTROL bitmap with a new CONTROL bitmap; this makes for a more sparkly dissolve. This was the technique I used in Excalibur (1983) and later in the title screen for Balance of Power (1985). The worst problems with this technique involve getting balanced numbers of bits in the bytes you use for CONTROL. I had to build big tables of semi-random numbers with the correct numbers of bits set for each iteration of the outer loop. Thus, I initialized an array SEMIRANDOM[1..15] OF [1..32] OF Integer. This gave me 32 random numbers of each type, one type containing a specified number of bits set.

Speed considerations
How fast is this technique? Not fast enough to handle an entire Macintosh screen, even in assembly language -- although even a simple full-screen blit is too slow for most animations. Its use is necessarily restricted to subsets of the screen, and small subsets at that. I found that dissolving bitmaps only 128x128 required recourse to assembly language. My guess is that, to use this with pure CopyBits calls in the Macintosh, you’d need to restrict yourself to bitmaps smaller than 64x64. With assembly language you can’t quite make 256x256 fast enough.

On an IBM, the situation is trickier. First off, color makes everything run more slowly, and the algorithm is more complex. Second, you may be required by marketing considerations to support slower processors. Considerable experimentation and judgement will be required.