THE apple® GAZETTE
Clearing The Apple II Low-Resolution Graphics Screen
Many applications require rapidly clearing the low-resolution graphics screen to black (COLOR = 0) or to some other color. In the latter case the process might be more accurately described as "back-grounding". Either way, this apparently simple operation can be done by several different methods. Each method will produce a distinctly different visual effect while in operation, although the end result will be the same. By doing the experiments to be described below, the experienced programmer can learn how to use the method best suited to his immediate purpose, and the novice programmer can learn some useful facts about the operation of the Apple low-resolution graphics. So go ahead and do the experiments on your Apple; you can't hurt it by pushing the keys (even the wrong keys), and you can learn a lot.
First of all, in order to see the effect of any kind of screen-clearing method it is best to begin with a screen that is loaded with colors and forms. You may do this in any way that pleases you; I have been using the following subroutine in Applesoft:
1000 GR 1010 FOR I = 0 TO 39 1020 FOR J = 0 TO 39 1030 COLOR = 1 + INT(15*RND(1)) 1040 PLOT J, I 1050 NEXT J, I 1060 FOR PAUSE = 0 TO 2000: NEXT PAUSE 1070 RETURN
Notice that this subroutine colors-in the so-called "mixed screen" — the top 40 lines, but not the bottom part reserved for text. If you wish to use, and color-in, the whole screen (48 graphics lines), then the first two lines of the Applesoft subroutine can be amended to:
1000 POKE -16302,0 : POKE -16304,0 1010 FOR I = 0 TO 47
etc. The line of POKEs turns on the "soft switches" governing the full-screen lo-res graphics (see pages 12-13 in the new Apple II reference manual).
Now that the screen is colored, let's clear it. The first method which is likely to occur to the average programmer is to write a couple of lines in Applesoft. Suppose you want to clear the screen to a particular background color, say C (C = 0 to 15). A program to do this for a mixed screen might look like this:
10 GOSUB 1000 : REM PAINT THE SCREEN 20 COLOR = C 30 FOR I = 0 TO 39 40 VLIN 39,0 AT I 50 NEXT I 60 END
Try it. The screen clears rather ponderously, like a stage curtain rolling across from left to right. If you want the curtain to move from right to left, just change line 30 to
30 FOR I = 39 TO 0 STEP-1
If you want it to operate on whole-screen graphics, line 40 should be altered to
40 VLIN 47,0 AT I
This method works fine, if you don't mind the relatively slow speed of the clearing operation. In fact, for some special effects it might even be preferred. Notice how you can control the direction of motion of the apparently rolling curtain. As an "exercise for the student", consider ,how you might change lines 30 and 40 so as to cause the curtain to appear to be rising upwards. That can be a rather pretty effect, especially if you don't just leave a blank screen but instead "paintin" a scene of some kind to coincide with the rising of the curtain (i.e., one horizontal line at a time, from bottom to top); it can look like a real stage curtain rising to reveal a scene already in place.
But what if you are not satisfied with the relatively slow speed with which an Applesoft program can clear the screen? If you don't mind being restricted to just a basic black clear, there are some dandy machine-language subroutines in the Apple's built-in ROM Monitor which are a lot faster. For mixed-screen graphics, try this little program:
10 GOSUB 1000 : REM PAINT SCREEN 20 CALL -1994 30 END
That's not only a heck of a lot faster, but pretty simple to use, too! If you're doing full-screen graphics, replace line 20 with
20 CALL -1998
Very neat. But this way you have no control over the direction of motion of the curtain, nor over the color to which the screen is cleared. Perhaps for your particular application neither of these restrictions makes any difference, in exchange for the very real advantages in speed and simplicity.
If you'd like to have your cake and eat it too, this can be arranged by POKEing a short machine-language subroutine into memory. Then you will be able to select your background color and still retain the speed advantage of the Monitor subroutine. You don't have to know anything about machine-language to do this, although for those who are curious I'll explain how it works in a few minutes. For the moment, just try the Applesoft program below:
10 GOSUB 1000 : REM PAINT SCREEN 20 FOR I = 768 TO 782 : REM POKE M/L SUB 30 READ J : POKE IJ 40 NEXT I 50 COLOR = C : REM YOUR CHOICE OF COLOR 60 CALL 768 : REM CALL THE SUBROUTINE 70 END 200 DATA 160, 39, 132, 45, 160, 39, 169, 0, 32, 40, 248, 136, 16, 248, 96
For full-screen graphics, replace the second number in the DATA statment ("39") by the number "47".
If you RUN this program you'll see that it works just like the Monitor version, except that now the screen clears to the selected color, C, instead of only to black (C = 0). It should perhaps be pointed-out that once you have POKEd this subroutine into the computer by executing lines 20 through 40, you can CALL it any number of times in your program without having to POKE it in again. Lines 20 - 40 only have to appear and be executed once in each session at the computer.
Although quite fast, this screen-clearing operation is by no means instantaneous: you can still perceive a curtain-like movement across the screen. What if that's not good enough? I recently wrote a game program in which I wanted the screen to flash suddenly white, to indicate that an enemy torpedo had broken through my screens and wiped me out. Even the machine-language routines are too slow to make a believable explosion flash — an instantaneous white-out. Well, this can in fact be done with the help of a somewhat longer machine-language subroutine which I will now describe. And if you're not into writing game programs, you might still like to be able to clear your screen instantaneously to provide nice sharp transitions from one scene to the next.
The new program looks like this:
70 FOR PAUSE = 0 TO 2000 : NEXT PAUSE 80 GOSUB 1000 : REM REPAINT SCREEN 90 FOR I = 800 TO 844 : REM NEW SUB 100 READ J : POKE IJ 110 NEXT I 120 COLOR = C 130 CALL 800 : REM CALL NEW SUBROUTINE 140 END 300 DATA 165, 48, 160, 120, 32, 45, 3, 160, 80, 32, 61, 3, 96, 136, 153, 0, 4, 153, 128, 4, 153, 0, 5, 153, 128, 5 310 DATA 208, 241, 96, 136, 153, 0, 6-, 153, 128, 6, 153, 0, 7, 153, 128, 7, 208, 241, 96
For full-screen graphics, replace the ninth number in DATA statement 300 ("80") by the number "120"
As before, once this new subroutine has been POKEd into memory it can be CALLed whenever you need it without having to rePOKE it (unless, of course, you happen to overwrite it in the meanwhile). This subroutine has been deliberately placed into different memory locations than the previous one, so they can coexist in your computer. Furthermore, the Applesoft routines associated with these two different methods were written in such a way that when both have been typed into your computer as indicated, they will run consecutively. When you type RUN, the screen first fills up with colors, pauses for a few seconds, and then is erased by the first machine-language subroutine. Then the screen fills up with a new random color pattern, pauses, and is suddenly cleared by the second subroutine. The speed difference between these two subroutines is readily apparent in operation.
Each of the several different screen-clearing methods which have been described above has its own special properties; they are all useful additions to your programming arsenal.
Now, for those who are interested, let me briefly discuss the functioning of the two machine-language subroutines. I will assume that the reader is at least somewhat familiar with 6502 Assembly Language and its standard notation.
The first subroutine, starting at location 768 decimal (equivalent to $0300 in hexidecimal) is just a very slightly altered version of the Monitor's routine which we used earlier by CALLing -1994. The Monitor version clears the screen by drawing vertical black lines one after another, exactly as we did it in our very first Applesoft program. The difference in speed between these routines simply reflects the well-known speed advantage of machine-language over Basic. Since the Monitor's version only paints in one color — black — it was changed to permit the color to be an input variable using the standard Applesoft COLOR = C instruction to define which one you want. In Assembler notation, this subroutine looks like this:
$0300: A0 27 BKGRND LDY #$27 ; Maximum Y for mixed-screen clear 0302: 84 2D STY V2 ; Store as line-bottom coordinate 0304: A0 27 LDY #$27 ; Rightmost X-coord (column) 0306: A9 00 CLRSCR LDA #$00 ; Will start clearing at top 0308: 20 28 F8 JSR VLINE ; Jump to line-drawing subroutine 030B: 88 DEY ; Next leftmost X-coord (column) 030C: 10 F8 BPL CLRSCR ; Loop until done 030E: 60 RTS ; Done. Return
For full-screen graphics, the number "27" in location $0301 is replaced by the (hexidecimal) number "2F"
The alert reader may have noticed that the color to be used did not appear anywhere in this subroutine. In fact, the Applesoft statement COLOR = C automatically stores the appropriate color constant in location $30 (decimal 48), where the Monitor routine VLINE can get at it. VLINE draws a single vertical line of the specified color.
Now, the flash-clear subroutine beginning at location 800 decimal ($0320 hexidecimal) works by taking advantage of the "memory-mapped" nature of the Apple's low-resolution screen. Each of the 1600 screen positions on the mixed screen or the 1920 screen positions on the whole screen is defined by a specific half-byte (four bits, or one "nybble") in memory. Since these four bits can represent one of sixteen different hex numbers ($0 through F), each screen position will have one of sixteen different colors depending on how the defining nybble has been set. The two nybbles in each byte define the color for two screen positions in the same column but consecutive rows, that is, two vertically-stacked colored squares. To color a given square it is only necessary to find its corresponding nybble and set it to the appropriate value.
Unfortunately, for some reason the Apple designers didn't arrange the memory locations in any simple consecutive fashion to correspond to the screen rows in numerical order. It requires a special algorithm to find the byte which represents the first square of each row; all the rest of the squares in that row will be represented by consecutive bytes after that. To further complicate matters, the last eight bytes in every 128 bytes do not correspond to any screen positions at all, but rather are used as "scratchpad" memory for whatever devices might be in the motherboard slots.
This last little detail makes the required subroutine for clearing the screen much more complicated than it would otherwise have to be. It is necessary to take the byte in location $30, which represents the chosen color nybble repeated twice, and store it in each byte of screen memory, being careful not to disturb those special bytes which are possibly being used as scratchpad. The address of the first and last effective byte of each row in screen memory has to be known in advance in order to perform this operation in the fastest possible time, without taking time to compute these addresses during the operation. All this has been done in the algorithm represented by the assembly-language subroutine below:
$0320: A5 30 FLASH LDA COLOR ; Get selected color byte 0322: A0 78 LDY #$78 ; Prepare to fill 120 bytes 0324: 20 2D 03 JSR FILL1 ; Fill four sets of 120 bytes each 0327: A0 50 LDY #$50 ; Prepare to fill 80 bytes 0329: 20 3D 03 JSR FILL2 ; Fill four sets of 80 bytes each 032C: 60 RTS ; Done. Return. ; Subroutine FILL1 puts the selected color byte into ; each of four sets of 120 consecutive screen-memory ; bytes, being careful to avoid the scratchpad bytes at ; the end of each set. 032D: 88 FILL1 DEY 032E: 99 00 04 STA $400, Y 0331: 99 80 05 STA $480, Y 0337: 99 80 05 STA $500, Y 033A: D0 F1 STA $580, Y 033C: 60 BNE FILL1 RTS ; Subroutine FILL2 puts the selected color byte into each ; of four sets of 80 consecutive screen-memory bytes. ; These are the "short lines", leaving out at the end of ; each one of the four text lines at the bottom of the ; mixed screen. 033D: 88 FILL2 DEY 033E: 99 00 06 STA $600, Y 0341: 99 80 06 STA $680, Y 0344: 99 00 07 STA $700, Y 0347: 99 80 07 STA $780, Y 034A: D0 F1 BNE FILL2 034C: 60 RTS
For full-screen graphics, the "short lines" of the subroutine FILL2 become full-length lines as in FILL1, which is accomplished simply by changing the constant "$50" in location $0328 to a "$78".
And that's how we clear the screen in a flash. But before I quit, I'd like to leave you with one more little idea. If, instead of setting the color byte by an Applesoft line of the form COLOR = C, you simply POKE into location 48 (decimal) any integer less than 256 (decimal), you may get a surprise. Depending on what integer you POKE, the screen may "clear" to a pattern of horizontal stripes! I'll bet that some clever reader out there will find some interesting and unexpected application for it.