One of the most spectacular effects
possible on any micro is fine scrolling. I recently read a review
for a BBC micro program in which the fine scrolling was praised.
The reviewer went on to say that this effect had needed the shifting
of more than 20,000 bytes! The same scrolling could be achieved
on an Atari by manipulating just a couple of dozen bytes as the
Atari has inbuilt hardware scrolling - a feature otherwise found
on much more expensive machines. As you will know, scrolling can
take place in two directions, horizontal and vertical (the frequently
seen diagonal scrolling is a combination of the two). Let us consider
vertical scrolling first, as it is slightly easier to implement
than the horizontal effect.
Coarse scrolling (the type you
see when LISTing a BASIC program) is easily achieved by manipulation
of the DL, as demonstrated in Listing 17. If you have followed and
understood this article so far, you should find it easy to see how
this program works. It first points the display memory to the lowest
RAM of the Atari then coarse scrolls over the entire memory space
of the computer. You will remember that the LMS instruction at the
start of any DL points to the first byte of screen memory, which
is displayed at the top lefthand corner of the screen. By adding
the number of bytes used in one mode line (40 bytes in the case
of Graphics 0) to the LMS operand bytes we cause the display to
move up by one line. Repeating this process makes the display scroll
Now coarse scrolling is not particularly
attractive, and it would be much better if we could scroll over
a smaller distance, such as one scan line at a time. The Atari provides
the facility to do just this - the register VSCROL at location 54277
(D405 hex). POKEing this register with a number from zero to 16
causes the display to scroll over that number of scan lines. However,
when fine scrolling using this register, you must carry out one
further step, that is to set the vertical fine scroll bits in the
DL. This is done by adding 32 to the instruction code for each mode
line you wish to scroll. Unless you do this, altering VSCROL will
have no effect. Note that you do not need to set the vertical scroll
bit on every mode line, unless of course you want the whole screen
to scroll. Once this is done, incrementing VSCROL scrolls the screen
upwards, decrementing VSCROL scrolls the screen down.
There is however one snag, which
you may already have spotted. VSCROL can only be POKEd with a number
of16 or less. How then do we scroll over a larger distance than
16 scan lines? The solution is in fact quite simple. We fine scroll
over the number of scan lines needed to make up one mode line minus
one (using VSCROL) then reset VSCROL and complete the scroll by
carrying out a coarse scroll. In case that isn't entirely clear
(!), Figure 2 should provide additional clarification. I am sure
that many of you will have seen this little diagram or something
similar in other articles on scrolling, but I repeat it here as
it is so useful.
Figure 2. Use of continued fine and course scrolling with register
Downward scrolling is achieved
by reversal of the process. Set VSCROL initially not to zero but
to the number of scan lines making up one mode line (see Table 1)
then decrement VSCROL to one. The scroll is completed by decrementing
the LMS operand bytes by the appropriate number, resetting VSCROL
at the same time.
You can fine scroll from BASIC
but the results are not particularly good. Listing 18 is an example.
The program first sets the vertical fine scroll bits on every line
in the DL (line 40) and then scrolls the display using combined
fine and coarse scrolling as described above. Straightaway you will
notice a couple of problems. Firstly, if you look carefully you
will see that the bottom line of the display does not scroll in
properly but jumps into place. This can be avoided very easily by
not setting the vertical fine scroll bit on the last line of your
scrolling display (in this case, the bottom line of the screen).
This allows the last line to act as a buffer for the next line to
scroll in. To see this, change the FOR...NEXT loop in line 40 to
read FOR J=6 TO 27, then rerun the program. The last line now scrolls
smoothly into place.
Secondly, notice that frequently
the screen jumps or flashes. This is an unavoidable effect of fine
scrolling from BASIC and occurs when VSCROL is changed while the
screen is being drawn. This distracts Antic and causes the unpleasant
glitches. The only solution is to change VSCROL during the vertical
blank period, which can only be done in machine language. If you
now add Listing 19 to Listing 18 you will finally get a smooth fine
scroll demonstration. This is a simple VBI routine to scroll the
display, and the assembler source code is provided in Listing 20.
This demonstration does however
show one last problem associated with vertical fine scrolling. As
you watch the display, you will see that every so often the display
suddenly changes. This is due to the limitation of Antic's memory
counter discussed earlier in this article, namely that it cannot
cross a 4K memory boundary. In a real application, if you wished
(and you probably would) to scroll over an area of greater than
4K, then one way around the problem would be to organise the screen
memory in discrete blocks starting at 4K RAM boundaries. Then, on
approaching the end of a 4K block, you would change the LMS operand
bytes in the DL to point to the next block, thus resetting the memory
counter. Of course, you would have to ensure that the first screen
of the new block was the same as the last screen of the previous
block or the picture would appear to suddenly change completely!
As you can see then, more than
anything else scrolling demands precise memory management - something
you don't normally have to worry much about. This is further emphasised
when setting up for horizontal scrolling.
The difficulty is that while graphics
mode lines appear completely separate on the screen, they are not
so in RAM. The bytes for one line follow directly on from those
of the previous line. Thus, if you attempted (for example) to scroll
the third line of a screen, the contents of line four would scroll
into line three, line five into line four, and so on. However, by
organising the screen memory differently it is easy to get around
this problem, and horizontal scrolling then becomes easier if anything
than vertical scrolling. What you do is direct each line you wish
to scroll to its own separate area of memory, and this is done by
setting an LMS instruction on each line to be scrolled. As always,
an example helps to clarify the position.
Listing 21 arranges for a line
of text in Graphics 2 to horizontally coarse scroll across the screen.
It first sets up a new DL in page six, then the 6th mode line down
is directed to a different memory area (actually page zero) than
the rest of the screen by its own LMS code. The 7th mode line is
then directed back to the regular screen memory by another LMS instruction.
Incrementing the LMS operand low-byte for the 6th mode line causes
right-to-left scrolling, and when the end of page zero is reached
the pointer is directed back to the start of the page. One point
to note here, location 255 is of course the last location in page
zero, but since the mode line itself takes 20 bytes, we use 255-20=235
as the limiting point for return to the start of the page. If you
look carefully, you can see that the display suddenly changes completely
when the return to the start of the page occurs. As an exercise,
you might like to arrange this program so that each mode line displays
and scrolls a different page in memory. If you get stuck, De Re
Atari (page 6-4) contains just such a program to study.
Once memory is arranged in this
way, fine scrolling can be implemented in the same fashion as vertical
fine scrolling. The register to use is HSCROL (location 54276, D404
hex) which will scroll up to 16 colour clocks horizontally in an
identical manner and with the same limitations as VSCROL. To scroll
over a large area therefore, we must combine fine and coarse scrolling
as before. To effect horizontal fine scrolling, the appropriate
lines of the DL must have the horizontal fine scroll bit set (add
16 to the DL mode line instruction). A slight complication is that
incrementing HSCROL scrolls the line from left to right, while as
we have seen incrementing the LMS operand moves it from right to
left. To fine scroll the same demonstration as in Listing 21, we
first set HSCROL to eight (Graphics 2 characters are eight colour
clocks wide) and decrement HSCROL to do the scroll. Unfortunately,
setting HSCROL to eight would move the line one character to the
right. To bring the line back to its correct starting position therefore
we set the LMS low-byte initially to one rather than zero. To see
how this works, add Listing 22 to Listing 21 and rerun the program.
Once again, we get those unpleasant glitches, and again we can only
get rid of these by scrolling during the vertical blank interval.
Before bringing in a VBI routine
to do this, let's look at a slightly more practical demonstration.
Listing 23 sets up a DL to scroll one line of Graphics 2 text as
before, but this time the text is a message that will scroll across
the screen. Line 30 reserves some memory (0.5K) to hold our message,
and the subroutine at line 270 POKEs the internal character codes
of the message, held in A$, into the reserved area. Incidentally,
512 bytes may not sound a lot, but since Graphics 2 screens only
use 20 bytes per line you can scroll through the equivalent of 12
screens with the use of just 3K of memory. I believe that Chris
Crawford used Graphics 2 for his celebrated 'Eastern Front' map,
the surprisingly small amount of memory used in scrolling text modes
explains how such a large map and complex program fits into 16K.
Take a look now at lines 300 to
320 where A$ is defined. You will see that the string starts with
two blank spaces. Why is this? Well, remember that when vertically
scrolling a display we dedicated one mode line to act as a buffer.
Setting the horizontal scroll bits in the DL makes Antic take an
extra 20% of memory per mode line to act as a scrolling buffer (in
the case of a 20-byte line, four extra bytes). On a normal width
playfield, these four bytes - two at each end of the line - are
not displayed on the screen, but we have to take them into account
all the same. If we didn't do this by starting the scrolling memory
area with two extra characters (blanks because we don't want them
to be seen) then we would lose the first two characters of the message.
Secondly, you will have noticed that the last 20 characters of the
string are identical to the first 20 characters. This is because
for the purposes of this demonstration we want the message to repeat
over and over again. However, directing the display memory back
to the start of the message when the end is reached would result
in a sudden change in the display. Try changing the last 20 characters
of the string to see what I mean. The way to avoid this is to make
the end of the scrolling memory identical to the start. Then, when
the memory pointer is redirected, no apparent change in the display
is seen. You should always do this if you want a wraparound display
(the same applies to vertical scrolling as well). Finally, the program
uses a simple VBI routine to perform the scroll (source code in
Well, that's about it! I have tried
to cover (in at least sufficient detail to get you started) the
various effects possible by altering and manipulating the display
list. I have used many sources for this article, but the most informative
were as follows:
De Re Atari (various authors)
from Atari Inc. See chapters 2, 5, and 6.
Mapping The Atari by Ian
Chadwick, from Compute! books.
Computer Animation Primer
by David Fox and Mitchell Waite from Byte Books. See chapters 5,
8, and 9.
First Book of Atari Graphics
(various authors) from Compute! Books. See chapter 2.
Tricky Tutorial 1: The Display
List from Santa Cruz educational software (manual and cassette/disk).
Your Atari Computer by Lon
Poole, Martin McNiff and Steven Cook from Osborne/McGraw Hill. See
chapter 9, pp. 294-306.