Scroll Your Way to the Top
A short course on coarse scrolling
By Chris ChabrisThis article serves as an introduction to the graphic animation technique called scrolling. The demonstration program requires BASIC and a minimum of 16K RAM, and runs on all Atari computers.
Scrolling is one of the easiest graphics techniques to implement on the Atari home computers. Reduced to its simplest form, it requires only one or two POKE commands. But scrolling is also the most difficult graphics effect to master. Coarse scrolling can be produced in BASIC, and is useful for most applications. I'll only touch on fine scrolling, which is beyond the scope of this article.
Before we delve into scrolling itself, we'll review the Atari display list. If you're familiar with the creation of custom display lists, however, you may want to skip to "Starting to Scroll."
The display list is a program for the Atari computer's ANTIC chip, which controls the display of text and graphics on the screen. It resides in RAM along with any user programs and is written by the Operating System (OS) whenever you use a GRAPHICS command.
The display list is always located in memory at the address given by:
Memory locations 560-561, which are labeled SDLSTL, contain a two-byte address that ANTIC uses to find its program. We'll use the variable DL to represent the address stored in these two bytes.
Display lists consist of four basic types of instructions: Blank, jump, Instruction Register (IR) and Load Memory Scan (LMS). A Blank instruction tells ANTIC to leave from one to eight scan lines blank. There are two different jump instructions. The first tells ANTIC to continue displaying data, but to display it from a different area of memory. The second signals a return to the beginning of the display list. This permits ANTIC to "draw" the screen that will follow the next vertical-blank period.
IR instructions range in value from two to 15 (decimal). They tell ANTIC to display one line of the corresponding mode. Note that IR, or ANTIC mode numbers, do not correspond to the OS Graphics Mode numbers. As Table 1 shows, custom display lists give you access to five modes that aren't available through the BASIC GRAPHICS statement. IR commands are not important for scrolling, but if you want to learn more about the construction of display lists, see "Display Lists Simplified" (Antic, P. 33, February/March 1983).
LMS instructions are the most important display-list instructions in terms of scrolling. One such command tells ANTIC to display a line of an IR mode. Two bytes must immediately follow an LMS instruction; these specify the address in memory from which the information to be displayed must be retrieved. To scroll a screen, all you need to do is modify this address.
Figure 1 should help you to understand these concepts more fully. It depicts a Mode 2+16 screen and its display list. Remember, the display list begins in memory at address DL.
In this listing, location DL + 3 holds the LMS instruction byte that specifies IR mode 7 or OS mode 2. To convert an IR instruction to an LMS, just add 64 (see Table 1). Bytes DL + 4 and DL + 5 are the two-byte number that provides the address of screen memory according to this familiar equation:
SCRN = PEEK(DL+4)+256*PEEK(DL+5)
We'll use the variable SCRN to refer to the address of screen memory that is specified after the first LMS command.
TABLE 1 ANTIC Instructions BASIC IR LMS Mode number instruction instruction 0 2 66 - 3 67 - 4 68 - 5 69 1 6 70 2 7 71 3 8 72 4 9 73 5 10 74 6 11 75 - 12 76 7 13 77 - 14 78 8-11 15 79 NOTES: A) Multiples of 16 (from 0 to 112) cause 1 to 8 scan lines to appear in the background color. B) To cause a display list interrupt (DLI), add 128 to the ANTIC instruction (IR or LMS). C) GTIA modes (9,10,11) all use IR instruction 15 and are selected by using location 623 (GPRIOR). For more information, see Antic, "Window on GTIA," p. 48, April 1983.
Starting to ScrollWe're now ready to discuss scrolling. Note that, in Figure 1, the first line of screen memory is found at memory locations SCRN to SCRN+19 and the last line is found at SCRN+220 to SCRN + 239.
What would happen if we were to increase the value of SCRN by 20 and POKE it back into the display list? Simply this: The characters previously stored at SCRN+20 to SCRN+39 would be displayed on the top line, the characters at SCRN+40 to SCRN+59 on the second line, and so on, until the tenth line were reached.
Here, the characters previously stored at SCRN+240 to SCRN+259 would be displayed. These characters wouldn't have been on the screen previously. In effect, this technique causes the screen's bottom line (the line "beneath" the display) to scroll up into the display, and the top line from SCRN to SCRN+19 to scroll off the screen. Figure 2 shows the new display and its display list.
Similarly, if the value of SCRN were decreased by 20, each line would scroll down. A new first line would appear, and the bottom line would scroll off the bottom of the screen, as seen in Figure 3. As you might guess, this process is called vertical scrolling, because the lines of displayed characters move up or down.
It is also an example of coarse scrolling, because the display is moved in increments that are as high as an entire character. This is a relatively large distance (in this case, it's 1/12 of the total display height). Fine scrolling allows you to scroll the display in increments that are only fractions of a character's height. This produces motion that is much less abrupt.
To put the new value of SCRN into the display list, in order to scroll the screen, we use the familiar formula for two-byte numbers:
SCRN=SCRN+20:REM To scroll down
POKE DL+4,SCRNL:POKE DL+5,SCRNH
The third and fourth lines take a two-byte address that is stored in a variable and break it into two variables. These are then POKED back into memory. This is not the most efficient method in BASIC, but it will do for now.
Horizontal ScrollingLet's return to our original display (Figure 1), and see what happens if we increase SCRN by one. The answer is that all of the characters are pushed one space to the left. But this does not constitute horizontal scrolling, because it causes the leftmost character on lines 1 through 11 to move to the right end of the line above it, and also causes a character from non-displayed RAM to sneak into the lower-right-hand corner of the display at the end of line 11. As a result, this method does not effect true horizontal scrolling.
The natural arrangement of screen memory, as shown in Figure 1, is responsible for our problem here. In this arrangement, a number of 20-character lines, or 20-byte blocks of memory, are stacked one on top of the other. This is a logical arrangement and is well suited to vertical scrolling, but a variation is required for horizontal scrolling. This configuration is shown in Figure 4.
Note that each line in Figure 4 is forty characters long - or twice the length of a normal Graphics Mode 2+16 line. This creates a total display area that is twice as large as the normal screen memory. Consequently, we can now scroll left and right across the memory area.
But to do so, we need to use the rewritten display list that accompanies Figure 4. It includes an LMS instruction for each of the twelve lines, and increases the address following each instruction by forty bytes. When ANTIC reads this display list, it begins each 20-byte displayed line 40 bytes ahead of the previous one (in memory). The result is a display of the left half of the total memory area. To scroll the screen to the right or left, simply loop through the display list, adding or subtracting one to or from each address. For example:
FOR L=DL+4 TO DL+37 STEP 3
MEM=MEM+1:REM Or "MEM=MEM-1"
POKE L,MEML:POKE L+1,MEMH
All that this really adds to the previous program fragment are the looping commands in the first and last lines. Otherwise, we're still basically modifying an address in memory.
As you can see, scrolling itself is not very difficult. Managing display memory (allocating space properly) and creating interesting displays (filling that space) are the aspects that make scrolling a demanding technique. Now, let's see how all of these elements can be combined effectively in a complete program.
Using the ProgramsType Listings 1 and 2 into your computer and verify your work with the TYPO program (Antic, p. 42, February 1984). RUN Listing 2 first to produce the disk files that Listing 1 will access. If you get a "BAD DATA" message, fix the guilty line and reRUN the program. Repeat the process until you see the "FILES GENERATED" message.
When RUN, Listing 1 will blank the screen for a few seconds while it creates a few machine-language subroutines, loads a character set and map file from disk, and writes the display list from Figure 4. Next, the upper-left-hand corner of a 24-fine by 40-character map will appear. Using a joystick plugged into Port 1, you can scroll the map in all eight directions. As you can see, it moves pretty quickly.
How the Program WorksSee Figure 5 for a diagram of the map in memory. The screen initially, displays the characters in the second quadrant of the map, but it can be "moved" to show any 12 x 20 block.
In line 1600, POKE 559,0 turns off the ANTIC chip; as a result, nothing is displayed on the screen. This increases processing speed by at least 25 percent. Lines 1800 to 4000 create three machine-language subroutines; the assembly-language source code for these is given in Listing 3. More on them later.
Line 4200 is very important. It first finds the number of 256-byte "pages" of memory available and reserves twelve of them (3K) for Our own use. Map screen data is loaded into an address 3K below the top of memory; the character set is loaded into an address 2K above that. If you POKE the map address minus one back into location 106, this tells the OS not to disturb the safe 3K while it is being used. POKE 756,CP tells ANIC where to find our redefined character set of map symbols.
Lines 4300-4400 use the machine-language subroutine in DF$ to load the character set and map files into memory at the defined addresses. This subroutine can load or save data to or from any area of RAM faster than BASIC can; see Listing 3 for details on using it in your own programs. Note that the file must be OPENed and CLOSEd from BASIC. Line 4500 POKEs the appropriate color-luminance values into the five color registers used in Graphics Mode 2.
Lines 4700-5000 build a display list by taking the value of MAP (equivalent to SCRN from above) and increasing it by 40 in a loop for each successive line. Before the 12 LMS-address pairs, the three 112's cause 24 blank scan lines to be displayed at the top of the screen. Then the bytes 65,0,6 tell ANTIC to start again at the beginning. This display list is stored in memory locations 1586 to 1577 (the first 42 bytes of Page 6 of memory), so 0 and 6 are also POKED into locations 560 and 561 (SDLSTL). Line 5100 restores the screen display and sets the initial X-Y coordinates.
The work of scrolling is accomplished by lines 5300-6200. First, the joystick is read and the variables H and V are set (according to the direction in which the joystick is pushed). A horizontal or vertical push will set one of the variables (leaving the other at zero), while a diagonal motion will set both. (H is +1 to scroll right or -1 to scroll left; V is +1 to scroll down or -1 to scroll up.)
The new X-Y coordinates are assigned in line 5800 and analyzed by the logic in line 5900. If they fall too far towards an edge of the map, scrolling is not executed, because this would result in a display of garbage data beyond the red border.
In lines 6000-6200, the program determines how many bytes to add to or subtract from each address in the display list, and makes the variable OFS (for offset) equal to 40 times the sum of the V offset and the H offset. This portion of the program combines the techniques we discussed for horizontal and vertical scrolling above. (Remember that for vertical scrolling, you add or subtract the line length; for horizontal scrolling, you add or subtract the number of bytes along the line.)
Next, the machine-language subroutine is invoked, using SCRP$ if the offset is positive or SCRN$ if the offset is negative. These tiny programs duplicate the loop shown above, but at a much faster speed. They fly through the display list, adding or subtracting the offset from each of the twelve addresses, just as we did in BASIC. Again, Listing 3 contains the source code for each of these subroutines. Line 6200 updates the X-Y coordinates and then reads the joystick again.
ConclusionWe've learned that horizontal scrolling usually requires machine language's speed, but that you can achieve vertical scrolling at a tolerable rate in BASIC. Although all of the examples here use a Graphics Mode 2 + 16 screen, any kind of display can be scrolled. For example, suppose you want to create a picture editing program using Graphics Mode 8. A Graphics Mode 8 screen is identical to four Graphics Mode 6 screens that are arranged two by two. Therefore, you can do detail work with a scrolling Graphics-Mode-6 display list.
If you're interested in creating maps that are similar to the one in Listings 1 and 2, you should consider Mapmaker from the Atari Program Exchange (APX). I used a modified version of its map-symbol character set for this article and created the four-screen map display with its editor.
The creation of scrolling and custom-display-list effects requires, above all, patient experimentation. Keep at it until the screen looks exactly the way you want it to!
Chris Chabris graduates this month from Bryam Hills High School in Armonk, New York. He will matriculate at Harvard College this fall.