Classic Computer Magazine Archive COMPUTE! ISSUE 144 / SEPTEMBER 1992 / PAGE G20

Smooth scrolling. (use of double buffering)
by Jim Butterfield

Pixel scrolling seems simple. Experimental POKES on a 64 to address 53265 or 53270 (hexadecimal Doll or D016) will show how the screen may be shifted one pixel.

The tough part comes when you reach the limit of a pixel register, which goes from 0 to 7. At that time, you must move every one of the characters onscreen to a new location and then reset the pixel count.

So, can we move 1000 bytes in less than 1/60 second? Practically speaking, it can't be done, not even at the blinding speed of machine language. And if we are working with a high-resolution screen, we need to move 8000 bytes. So many bytes, so little time. It's out of the question.

There is a way around it, though: double buffering. Here's how it works. We have two screen areas set up in memory. One screen is being displayed, and the other is being constructed. When the second screen is complete, we tell the video chip to switch its attention to the new location. It now becomes the "real" screen, and we can start to build a new display in the former screen-memory area.

It still takes time to do this, but the switch won't take place until the new screen is completely built. Both pixel scrolling and the screen switch benefit from careful timing. We must pull the switch during retrace to ensure that there will be no flicker or screen jump.

The following is a simple smooth-scroll program for the 64 that demonstrates this technique. The code is stored in the cassette buffer memory area. Because of its size, we'll focus our attention on select parts of the program. You may enter the BASIC program, run it, and then disassemble the machine language code if you want to see details.

Our two screen buffers are located at 32768 and 33792, hexadecimal 8000 and 8400. We build the new screen by copying characters from the other, active, screen. The direction of our scroll is up, so we drop the first 40 characters from the old screen, copy the rest, and then fill the bottom line of the new screen with space characters.

The program uses two indirect addresses to do this copying: $26/27 holds the "from" pointer, and $28/29 the "to" pointer. As we flip between the two screens, the two pointers are set appropriately.

The first thing the program must do is copy the screen. That occupies code from $033C to 037E. A short loop follows to pad the bottom line with space characters.

At $038A, we walk the old screen through its pixel scroll. Since we're scrolling in the up direction, our objective is to step the Y pointer from 7 down to 0. That pointer is stored in the video register at Doll, which also contain the video-enable signal as bit 4. So the value that we stuff into that register will step from $17 down to $10; we hold this value in the X register.

Before each pixel scroll, we wait for a screen retrace. We do this by watching that same register, Doll. Its two highest bits tell us about the raster. When the value of those two bits goes down, it's retrace time.

In fact, we wait for six retrace events. We don't want our pixel scroll to be too fast, or the user might miss it. Each retrace happens in about 1/60 second, so a loop of six retraces will slow our pixel movement to 10 per second. ; scroll seven pixel positions 038A LDX #$17

; wait about 1/10 second 038C LDY #$05

wait for screen retrace 038E LDA $D011 0391 AND #$C0 0393 CMP 03D0 0396 STA 03D0 0399 BCS $038E 039B DEY 039C BPL $038E

;do pixel scroll ;set up next 039E STX D011 03Al DEX 03A2 CPX #$10 03A4 BCS $038C

Now the pixel scroll has reached its limit. Our screen characters are set; we simply flip to the new screen. We must also return the pixel counter to its highest value. Moving the characters is the equivalent of eight bits of scrolling, so we back off seven bits to produce a net one-bit scroll. 03A6 LDX #$17 03A8 LDA $D018 03AB EOR #$10 03AD STA $D018 03BD STX $D011

The above coding puts the two store instructions close together to minimize possible screen jump. In fact, we're quite safe, since all this is being done in retrace time.

A small amount of extra coding is added. Its purpose is to reposition the cursor so that the next time we print, the information will go to the new screen and be printed at the appropriate place. This involves storing a new value in address $0288. The Kernal routines use this address to find the screen.

The program code shows a character screen moving in one direction only. Once you understand the principles involved, you can take on more ambitious jobs. BX 100 DATA 169,40,133,3

8,169,0,133,40,16

2,128,160,132,134

39,132,41,169,16 HP 110 DATA 44,24,208,24

0,4,134,41,132,39

,162,0,160,0,177,

38,145,40,200,1

,40 DC 120 DATA 144,247,24,

65,38,105,40,133,

38,144,2,230,39,2

4,165,40,105,40,1

33,40 FM 130 DATA 144,2,230,41

,232,224,24,144,2

18,169,32,160,0,1

45,40,200,192,40 SF 140 DATA 144,249,162,

23,160,5,173,17,2

08,41,192,205,208

,3,141,208,3,176,

243 EQ 150 DATA 136,16,240,1

42,17,208,202,224

,16,176,230,162,2

3,173,24,208,73 AB 160 DATA 16,141,24,20

8,142,17,208,173,

136,2,73,4,141,13

6,2,169,145,32,2

0,255 XS 170 DATA 169,13,76,21

0,255 EB 200 FOR J=828 To 964 DP 210 READ X CG 220 T=T+X FQ 230 POKE J,X QF 240 NEXT J MJ 250 IF T<>15776 THEN

{SPACE}STOP BD 280 POKE 55,0:POKE 56

,128:CLR DX 300 POKE 53265,23 MG 310 POKE 56576,5 XB 320 POKE 53272,4 KH 330 POKE 648,128 KD 340 PRINT CHR$(147) JE 350 FOR J=1 To 22 CS 360 PRINT PS 370 NEXT J HK 380 PRINT "THIS IS AN

EXAMPLE"; MQ 390 SYS 828 FA 400 PRINT "OF PIXEL S

CROLLING"; HQ 410 SYS 828 AJ 420 PRINT "WITH DOUBL

E BUFFERING"; XS 430 SYS 828 FF 440 PRINT "I HOPE YOU

LIKE IT"; HX 450 SYS 828 DS 460 FOR J=1 TO 1000:N

EXT J ER 800 POKE 648,4 GJ 810 PRINT "END!" JM 820 POKE 53272,20 FJ 830 POKE 56576,7 DF 840 POKE 53265,27 BD 850 REM NEXT POKE OPT

IONAL KA 860 POKE 55,0:POKE 56

,160:CLR