Conventional computers use coarse scrolling; in this type of scrolling, the pixels that hold the characters are fixed in position on the screen and text is scrolled by moving bytes through the screen RAM. The resolution of the scrolling is a single character pixel, which is very coarse. The scrolling this produces is jerky and quite unpleasant. Furthermore, it is achieved by moving up to a thousand bytes around in memory, a slow and clumsy task. In essence, the program must move data through the playfield to scroll.
Some personal computers can produce a somewhat finer scroll by drawing images in a higher resolution graphics mode and then scrolling these images. Although higher scrolling resolution is achieved, more data must be moved to attain the scrolling and the program is consequently slowed. The fundamental problem is that the scrolling is implemented by moving data through the screen area.
There is a better way to achieve coarse scrolling with the ATAR.1 400/ 800: move the screen area over the data. The display list opcodes support the Load Memory scan feature. The LMS instruction was first described in Section 2 and tells ANTIC where the screen memory is. A normal display list will have one LMS instruction at the beginning of the display list; the RAM area it points to provides the screen data for the entire screen in a linear sequence. By manipulating the operand bytes of the LMS instruction., a primitive scroll can be Implemented. In effect, this moves the playfield window over the screen data. Thus, by manipulating just 2 address bytes, you can produce an effect identical to moving the entire screen RAM. The following program does just that:
10 DLIST=PEEK(560)+256*PEEK(561):REM Find display list
20 LMSLOW=DLIST+4:REM Get low address of LMS operand
30 LMSHIGH=DLIST+5:REM Get high address of LMS operand
40 FOR 1=0 TO 255:REM Outer loop
50 POKE LMSHIGH,
60 FOR J=O TO 255:REM Inner loop
70 POKE LMSLOW,J
80 FOR Y=1 TO 50:NEXT Y:REM Delay loop
90 NEXT J
100 NEXT 1
10 GRAPHICS 0
20 DLIST=PEEK(560)+256*PEEK(561)
30 LMSLOW=DLIST+4
40 LMSHIGH=DLIST+5
50 SCREENLOW=0
60 SCREENHIGH=0
70 SCREENLOW=SCREENLOW+40:REM Next line
80 IF SCREENLOW<256 THEN GOTO 120:REM Overflow?
90 SCREENLOW=SCREENLOW-256:REM Yes, adjust pointer
100 SCREENHIGH=SCREENHIGH+1
110 IF SCREENHIGH=256 THEN END
120 POKE LMSLOW,SCREENLOW
130 POKE LMSHIGH,SCREENHIGH
140 GOTO 70
The solution is to expand the screen data area and break it up into a series of independent horizontal line data areas. Figure 6-1 schematically illustrates this idea:
normal data arrangement | arrangement for horizontal scroll |
Figure 6-1 Arranging Screen RAM
The first step in implementing pure horizontal scroll is to determine the total horizontal line length and allocate RAM accordingly. Next, you must write a completely new display list with an LMS instruction on each mode line. The display list will of course be longer than usual, but there is no reason why you cannot write such a display list. What values do you use for the LMS operands? It is most convenient to use the address of the first byte of each horizontal screen data line. There will be one such address for each mode line on the screen. Once the new display list is in place, ANTIC must be turned onto it and screen data must be written to populate the screen. To execute a scroll, each and every LMS operand in the display list must be incremented for a rightward scroll or decremented for a leftward scroll. Program logic must ensure that the image does not scroll beyond the limits of the allocated RAM areas; otherwise, garbage displays will result. In setting up such logic, the programmer must remember that the LMS operand points to the first screen data byte in the displayed line. The maximum value of the LMS operand is equal to the address of the last byte in the long horizontal line minus the number of bytes in one displayed line. Remember also that the LMS value should not come within one screen display line's length (in bytes) of a 4K address boundary, or the wrong data will be displayed due to LMS counter rollover.
As this process is rather intricate, let us work out an example. First, we must select our total horizontal line length. We shall use a horizontal line length of 256 bytes, as this will simplify address calculations. Each horizontal line will then require one page of RAM. Since we will use BASIC mode 2, there will be 12 mode lines on screen; thus, 12 pages or 3K of RAM will be required. For simplicity (and to guarantee that our screen RAM will be populated with nonzero data), we will use the bottom 3K of RAM. This area is used by the OS and DOS and so should be full of interesting data. To make matters more interesting, we'll put the display list onto page 6 so that we can display the display list on the screen as we are scrolling. The initial values of the LMS operands will thus be particularly easy to calculate; the low order bytes will all be zeros and the high order bytes will be (in order) 0, 1, 2, etc. The following program performs all these operations and scrolls the screen horizontally:
10 REM first set up the display list
20 POKE 1536,112:REM 8 blank lines
30 POKE 1537,112:REM 8 blank lines
40 POKE 1538,112:REM 8 blank lines
50 FOR 1=1 TO 12:REM Loop to put in display list
60 POKE 1536+3*1,71:REM BASIC mode 2 with LMS set
70 POKE 1536+3*1+1,0:REM Low byte of LMS operand
80 POKE 1536+3*1+2,1:REM High byte of LMS operand
90 NEXT I
100 POKE 1575,65:REM ANTIC JVB instruction
110 POKE 1576,0:REM Display list starts at $0600
120 POKE 1577,6
130 REM tell ANTIC where display list is
140 POKE 560.0
150 POKE 561,6
160 REM now scroll horizontally
170 FOR 1=0 TO 235:REM Loop through LMS low bytes
175 REM we use 235 --- not 255 --- because screen width is 20 characters
180 FOR J=1 TO 12:REM for each mode line
190 POKE 1536+3*J+1,1:REM Put in new LMS low byte
200 NEXT J
210 NEXT 1
220 GOTO 170:REM Endless loop
The next step is to mix vertical and horizontal scrolling to get diagonal scrolling. Horizontal scrolling is achieved by adding 1 to or subtracting 1 from the LMS operand. Vertical scrolling is achieved by adding the line length to or subtracting the line length from the LMS operand. Diagonal scrolling is achieved by executing both operations. There are four possible diagonal scroll directions. If, for example, the line length is 256 bytes and we wish to scrolldown and to the right, we must add 256+(-1)=255 to each LMS operand in the display list. This is a 2-byte add; the BASIC program example given above avoids the difficulties of 2-byte address manipulations but most programs will not be so contrived. For truly fast two-dimensional scrolling, assembly language will be necessary.
All sorts of weird arrangements are possible if we differentially
manipulate the LMS bytes. Lines could scroll relative to each other or
hop over each other. Of course, some of this could be done with a
conventional display but more data would have to be moved to do it.
The real advantage of LMS scrolling is its speed. Instead of
manipulating an entire screenfull of data, many thousands of bytes in
size, a program need only manipulate two or perhaps a few dozen bytes.
FINE SCROLLING
The second important scrolling facility of the ATARI Computer is the
fine scrolling capability. Fine scrolling is the capability of scrolling a
pixel in steps smaller than the pixel size. (Throughout this section the
term pixel refers to an entire character, not to the smaller dots that make
up a character.) Coarse scrolls proceed in steps equal to one pixel
dimension; fine scrolls proceed in steps of one scan line vertically and
one color clock horizontally. Fine scrolling can only carry so far; to get
full fine scrolling over long distances on the screen you must couple
fine scrolling with coarse scrolling.
There are only two steps to implement fine scrolling. First, you set the fine scroll enable bits in the display list instruction bytes for the mode lines in which you want fine scrolling. (In most cases you want the entire screen to scroll so you set all the scroll enable bits in all the display list instruction bytes.) Bit D5 of the display list instruction is the vertical scroll enable bit; bit D4 of the display list instruction is the horizontal scroll enable bit. You then store the scrolling value you desire into the appropriate scrolling register. There are two scrolling registers, one for horizontal scrolling and one for vertical scrolling. The horizontal scroll register (HSCROL) is at $D404; the vertical scroll `register (VSCROL) is at $D405. For horizontal scrolling, you store into HSCROL the number of color clocks by which you want the mode line scrolled. For vertical scrolling, you store into VSCROL the number of scan lines that you want the mode line scrolled. These scroll values will be applied to every line for which the respective fine scroll is enabled.
There are two complicating factors that you encounter when you use fine scrolling. Both arise from the fact that a partially scrolled display shows more information than a normal display. Consider for example what happens when you horizontally scroll a line by half a character to the left. There are 40 characters in the line. Half of the first character disappears off of the left edge of the screen. The 40th character scrolls to the left. What takes its place? Half of a new character should scroll in to take the place of the now scrolled 40th character. This character would be the 41st character. But there are only 40 characters in a normal line. What happens?
If you have implemented coarse scrolling, then the 41st character suddenly appears on the screen after the first character disappears off of the left edge. This sudden appearance is jerky and unsightly. The solution to this problem has already been built into the hardware. There are three display options for line widths: the narrow playfield (128 color clocks wide), the normal playfield (160 color clocks wide) and the wide playfield (192 color clocks wide). These options are set by setting appropriate bits in the DMACTL register. When using horizontal fine scrolling, ANTIC automatically retrieves more data from RAM than It displays. For example, if DMACTL is set for normal playfield, which in BASIC mode 0 has 40 bytes per line, then ANTIC will actually retrieve data at a rate appropriate to wide playfield --- 48 bytes per line. This will throw lines off horizontally if it is not taken into account. The problem does not manifest itself if the you have already organized screen RAM into long horizontal lines as in Figure 6-1.
The corresponding problem for vertical scrolling can be handled in either of two ways. The sloppy way is to ignore it. Then you will not get half-images at both ends of the display. Instead, the images at the bottom of the display will not scroll in properly; they will suddenly pop into view. The proper way takes very little work. To get proper fine scrolling into and out of the display region you must dedicate one mode line to act as a buffer. You do this by refraining from setting the vertical scroll bit in the display list instruction of the last mode line of the vertically scrolled zone. The window will now scroll without the unpleasant jerk. The screen image will be shortened by one mode line. An advantage of scrolling displays now becomes apparent. It is quite possible to create screen images that have more than 192 scan lines in the display. This could be disastrous with a static display, but with a scrolling display images which are above or below the displayed region can always be scrolled into view.
Fine scrolling will only scroll so far. The vertical limit for fine scrolling is 16 scan lines; the horizontal limit for fine scrolling is 16 color clocks. If you attempt to scroll beyond these limits, ANTIC simply ignores the higher bits of the scroll registers. To get full fine scrolling (in which the entire screen smoothly scrolls as far as you wish) you must couple fine scrolling with coarse scrolling. To do this, first fine scroll the image, keeping track of how far it has been scrolled. When the amount of fine scrolling equals the size of the pixel, reset the fine scroll register to zero and execute a coarse scroll. Figure 6-2 illustrates the process.
Figure 6-2 Linking Fine Scroll to Coarse Scroll
1 HSCROL=54276
2 VSCROL=54277
10 GRAPHICS 0:LIST
20 DLIST=PEEK(560)+256*PEEK(561)
30 POKE DLIST+10,50:REM Enable both scrolls
40 POKE DLIST+11,50:REM Do it for two mode lines
50 FOR Y=O TO 7
60 POKE VSCROL,Y:REM Vertical scroll
70 GOSUB 200:REM Delay
80 NEXT Y
90 FOR X=0 TO 3
100 POKE HSCROL,X:REM Horizontal scroll
110 GOSUB 200:REM Delay
120 NEXT X
130 GOTO 40
200 FOR J=1 TO 200
210 NEXT J:RETURN
There are many other applications of this technique. Any very large image that can be drawn with character graphics is amenable to this system. (Scrolling does not require character graphics. Map graphics are less desirable for scrolling applications because of their large memory requirements.) Large electronic schematics could be presented in this way. The joystick could be used both to scroll around the schematic and to indicate particular components that the user wishes to address. Large blueprints or architectural diagrams could also be displayed with this technique. Any big image that need not be seen in Its entirety can be presented with this system.
Large blocks of text are also usable here, although it might not be practical to read continuous blocks of text by scrolling the image. This system is more suited to presenting blocks of independent text. One particularly `exciting idea is to apply this system to menus. The program starts by presenting a welcome sign on the screen with signs indicating submenus pointing to other regions of the larger image. "This way to addition" could point up while "this way to subtraction" might point down. The user scrolls around the menu with the joystick, perusing his options. When he wishes to make a choice, he places a cursor on the option and presses the red button. Although this system could not be applied to all programs, it could be of great value to certain types of programs.
There are two "blue sky" applications of fine scrolling which have not yet been fully explored. The first is selective fine scrolling, in which different mode lines of the display have different scroll bits enabled. Normally you would want the entire screen to scroll, but it is not necessary, to do so. You could select one line for horizontal scrolling only, another line for vertical scrolling only, and so forth. The second blue sky feature is the prospect of using display list interrupts to change the HSCROL or VSCROL registers on the fly. However, changing VSCROL on the fly is a tricky operation; it would probably confuse ANTIC and produce undesirable results. Changing HSCROL is also tricky but might be easier.