by Ron Goodman
There's a lot of computer animation today, and many Atari owners probably wish they could do some of the animation that they see in the movies and the video arcade. But there are several problems. Most computer animation done in movies is not produced "real-time." That is to say that it's created a frame at a time and then photographed. From there it may be modified with both digital and analog filters, so each frame may end up taking several minutes to produce. Some of the best quality graphics produced with techniques such as "ray-tracing" may even take several hours per frame to create on a mainframe computer.
The second problem is of course that an Atari is not a mainframe computer. The Atari instead has a relatively slow 6502 microprocessor. With the overhead added by using a high-level language like Atari BASIC, most programmers throw up their hands in disgust.
Some people abandon BASIC and try assembly language. This is a good recourse, but even Atari assembly is not that fast, and many people don't want to give up the ease of using a high-level language.
In this article I will demonstrate my solution to this problem using two machine language routines. They will allow you to do your entire animation program in BASIC without ever touching an editor/assembler and without buying a new computer! Because, in spite of the weaknesses of a 6502 computer, the Atari computer is still the best computer for graphics and animation under $1,000, except perhaps for the Atari STs.
What
is animation?
The process of animation involves displaying
pictures, one after the other, usually in an attempt to simulate
motion. Cartoonists have used the method for years, and in reality
moviemakers do basically the same thing too (although they don't call
it animation, since the pictures are generated from a camera rather
than an artist or computer). Different methods of animation generally
differ in the way that the images are created, and the speed that the
images are displayed (frames per second.)There are two general categories of computer-graphics animation, although they often can be found combined into a hybrid form. The first is frame generating, where the entire frame is created, displayed and then erased when the next frame is generated. The second method is frame modification. In this method an original image is displayed and then changed only in the parts where something is supposed to move.
Frame generation is very flexible and usually relatively easy to program. The first problem is that it can be slow, since even the slightest change requires that the entire picture be erased and regenerated. The second is that it usually requires twice as much video memory: one chunk for the picture being displayed and another chunk for the image being generated.
Frame modification is often much faster, but it's not as flexible and often does not look as good as frame generation. It's unfortunately limited to simple animation-unless you want your program to get very slow and complex. This method is also usually less memory consuming than frame generation, although this advantage can be sacrificed in order to use a workscreen to make smooth picture transitions like frame generation. Frame modification is what most BASIC programmers like to use because of the speed advantage.
Listings 1 and 2 are two programs which visibly do the same animation, but Listing 1 uses frame generation and Listing 2 uses frame modification. The programs move a horizontal line from the far left of the screen to the far right. In frame generation, we display a line at the far left (0,100). Then that line is erased and a new line is displayed at (1,100)-then (2,100), (3,100) and so on until it reaches the far right. This method is slow because the entire line must be redrawn to move it. Also, increasing the length of the line would slow down the program. This method is flexible. The line could easily be made to move two pixels at a time by just changing the X =X + 1 to an X =X + 2 or made to move vertically by changing the value of Y
The frame modification routine has a different approach. It draws the line at the far left (0,100). Then it erases the leftmost pixel of the line and adds a pixel to the right end over and over until the line appears to have moved to the far right of the screen. This method is fast because only two pixels have to be drawn per frame. The line could have been 100 pixels in length with no loss in speed, since the line is not being redrawn each frame. However, the movement is not as flexible. Since we are using a trick to move the line, moving two pixels at a time would not be a simple change. And moving the line vertically would be completely different.
For moving a line across the screen, most people choose frame modification because speed is the most important factor. But type in the two programs in Listings 3 and 4. They each have approximately the same output-four simple stick figures bounce around in a box with a square inside it. In frame modification (Listing 4) the action is sloppy. When part of the picture crosses the inner square it erases it momentarily. In frame generation (Listing 3) the movement is smooth and no damage occurs when two objects cross paths. In addition, frame generation is slightly faster. Why? Because most of the picture changes each frame.
Using
frame generation
Some nice frame generation can be done on the Atari
since it has pageflipping abilities. This is the ability to tell the
computer where an image is stored in memory, which allows you to change
the Atari's screen from displaying one image to the next virtually
instantly. The program in Listing 5 is an optimized assembly language
listing of a program that will allow BASIC programmers to easily use
this feature. The program in Listing 6 is a BASIC program that can be
appended to the end of your BASIC animation program. A GOSUB to Line
30000 will load the machine-language routine from Listing 5 into Page 6
memory. Remember that Page 6 is unused by BASIC, so this routine is
safe and takes up no program memory.This program fools the Atari into displaying one image and working on another. The graphics commands DRAWTO and PLOT will draw the invisible background image to create the next frame while the current image is being displayed. Calling the machine-language routine with an X=USR(1536) will cause the invisible image to be displayed and the image being displayed to be disposed. Then you draw the next frame and do another X=USR(1536). The machine-language handles all the details in just a 15th of a second, so all you need to do is call X = USR(1536), draw an image, call X=USR(1536), draw next image, call X=USR(1536), draw next image, etc. Although it is not always necessary, it is a good general practice to call X = USR(1536) just after the GRAPHICS statement and before you begin drawing. This program will work in graphics mode 24, 9, 10 and 11 (24 is mode 8 without a text window).
What is the routine doing? First it modifies the display list to point to one chunk of memory. Next it adjusts the video memory pointer at locations 88 and 89 of BASIC to point at another chunk. DRAWTO and PLOT commands are drawn in the chunk pointed to by the video memory pointer and so are not seen. Then, the next time the machine-language routine is called, the pointers swap. The 7680 byte area of memory that was being displayed is filled with zeros (cleared) and is ready to be used for the next frame. And the 7680 byte chunk that was being worked on by DRAWTOs and PLOTs is now displayed.
Frame
generation is
very flexible and usually
relatively easy to
program. The first
problem is that it can
be slow, since even the
slightest change
requires that the entire
picture be erased and
regenerated,
very flexible and usually
relatively easy to
program. The first
problem is that it can
be slow, since even the
slightest change
requires that the entire
picture be erased and
regenerated,
The BASIC program in Listing 7 is an example of a complete frame-generation program. It's a clock program that updates its display about every ten seconds. The hands move smoothly because the picture appears to be drawn instantly. The clock chimes at the half hour and gongs at the hour. It has ten setable alarms. To set the alarms, press the space-bar while the program is running. To quit press ESCAPE. The alarms and the current time are maintained even if the program is stopped (or even deleted!), but the alarms will only sound while the program is running. The screen will progressively dim after a few minutes of inactivity instead of going into attract mode to protect the screen more effectively and attractively. This way the computer can be left on over-night or even for days.
The BASIC program in Listing 8 is another example. In this program you draw a line picture with the joystick. Do this by moving the graphics cursor to various points and pressing the joystick fire button. The program will connect the points. After you draw your picture, press START. Now the joystick will cause your picture to expand or contract by pushing up or down, and move left or right by pressing the stick left or right. Pressing the fire button will cause the picture to be rotated by ten degrees. The pictures are generated quickly and appear to be redrawn instantly. Unrestricted movement like this is easy with frame generation and the obvious choice over frame modification for such an application.
Using
frame modification
Using frame modification doesn't have to be choppy
and chunky. You can use the page-flipping technique that we used in
frame generation. Listing 9 is an assembly language program for this
purpose. It works in a different manner, of course. It must be called
before you begin drawing. Now all of your drawing is done in the
background screen. When the frame is ready to be displayed you do
another USR call and the frame is copied into the foreground for
display, leaving the background copy intact. Future modifications are
still done on the background. And whenever it is time for an update you
do another USR call. So all you need to do is X=USR(1664), draw the
picture, X=USR(1664), modify the picture, X=USR(1664) , modify the
picture, X = USR(1664), etc.Listing 10 can be appended to your BASIC program to load this routine. Like the frame generation program the machine language is stored in unused Page 6 so it doesn't use program memory. Note also that both Listing 6 and Listing 10 have unique line numbers and can be appended for combined frame modification and frame generation applications. The machine-language routines are also stored in different areas of Page 6 so that there is no conflict of memory there.
Other
methods of animation
The Atari has some special features for animation
that can be used. Player-missile graphics are useful for horizontal
animation, or if some machine language is used, for vertical animation
too. There is collision detection in hardware to simplify computations
for games, but player/missile graphics can also be used to simplify
animation computations. For more complete explanations of these
features, you should read De Re Atari.Ron Goodman is a computer music major at the California Institute of Technology. His greatest fascination is with computer graphics and computer music (MIDI/ST applications).
LISTING 1: BASIC
IQ 5 GOSUB 30000
RR 10 GRAPHICS 24:COLOR 1
PC 20 X=0:Y=100
OY 30 PLOT X,Y:DRAWTO X+50,Y:A=USRC1536)
DJ 40 X=X+1:IF X<268 THEN 30
RM 50 GOTO 10
TV 30000 RESTORE 30010:FOR X=1536 TO 1627
READ Y:POKE X,Y:NEXT X:RETURN
PW 30010 DATA 160,0,24,173,48,2,105,5,133
,203,173,49,2,105,0,133,204,165,203,10
5,96,133,205,165,204,105,0,133
QS 30020 DATA 206,173,49,2,56,233,31,141,
230,2,165,89,209,203,208,7,173,230,2,1
33,89,208,13,170,177,203,133
WW 30030 DATA 89,138,145,203,24,105,15,14
5,205,165,89,141,80,6,165,88,141,79,6,
169,0,162,30,153,80,127,200
WF 30040 DATA 208,250,238,80,6,202,208,24
4,104,96
LISTING 2: BASIC
RR 10 GRAPHICS 24:COLOR 1
PC 20 X=0:Y=100
KX 30 PLOT XY:DRAWTO X+50 ,Y
LJ 40 COLOR 0 PLOT X,Y:COLOR 1:PLOT X+51,
Y:X=X+1:IF X<268 THEN 40
RM 50 GOTO 10
LISTING 3: BASIC
IQ 5 GOSUB 30000
FH 10 GRAPHICS 24:SETCOLOR 2,0,0
IW 20 CX=160:CY=86:X=0:Y=0:DX=6:DY=5:T=1
GZ 30 COLOR 1:PLOT 67,20:DRAWTO 252,20:DR
AWTO 252,171:DRAWTO 67,171:DRAWTO 67,2
0
QC 40 PLOT 100,40:DRAWTO 219,40:DRAWTO 21
9,151:DRAWTO 100,151:DRAWTO 100,40
JZ 60 XX=CX+X:YY=CY+Y:GOSUB 1000
LI 76 XX=CX+X:YY=CY-Y:GOSUB 1000
KT 80 XX=CX-X:YY=CY+Y:GOSUB 1000
MC 90 XX=CX-X:YY=CY-Y:GOSUB 1000
VO 95 T=USR(1536)
UI 100 IF X=0 OR Y=0 THEN FOR A=50 TO 0 S
TEP -1:SOUND 0,A,12,A/3.23:FOR B=1 TO
10:NEXT B:NEXT A
HN 110 GOSUB 250:GOSUB 200
QC 130 GOTO 30
PT 200 X=X+DX:Y=Y+DY:RETURN
MM 250 IF ABS(Y)>53 THEN DY=-DY:GOSUB 300
LV 260 IF ABS(X)>83 THEN DX=-DX:GOSUB 300
ZM 270 RETURN
AF 300 FOR A=15 TO 0 STEP -0.2:SOUND 0,41
,12,A:NEXT A:RETURN
SM 1000 PLOT XX-5,YY-10:DRAWTO XX+5,YY-10
:DRAWTO XX+5,YY:DRAWTO XX-5,YY:DRAWTO
XX-5,YY-10:REM DRAW HEAD
VZ 1010 PLOT XX,YY:DRAWTO XX,YY+20:DRAWTO
XX-7,YY+29:PLOT XX,YY+20:DRAWTO XX+7,
YY+29:REM DRAW BODY AND LEGS
TB 1020 PLOT XX-6,YY+9:DRAWTO XX,YY+7:DRA
WTO XX+6,YY+9:REM DRAW ARMS
AI 1030 RETURN
TV 30000 RESTORE 30010:FOR X=1536 TO 1627
:READ Y:POKE X,Y:NEXT X:RETURN
PW 30010 DATA 160,0,24,173,48,2,105,5,133
,203,173,49,2,105,0,133,204,165,203,10
5,96,133,205,165,204,105,0,133
QS 30020 DATA 206,173,49,2,56,233,31,141,
230,2,165,89,209,203,208,7,173,230,2,1
33,89,208,13,170,177,203,133
WN 30030 DATA 89,138,145,203,24,105,15,14
5,205,165,89,141,80,6,165,88,141,79,6,
169,0,162,30,153,80,127,200
WF 30040 DATA 208,250,238,80,6,202,208,24
4,104,96
LISTING 4: BASIC
FM 10 GRAPHICS 24:SETCOLOR 2,0,0
GY 20 COLOR 1:PLOT 67,20:DRAWTO 252,20:DR
AWTO 252,171:DRAWTO 67,171:DRAWTO 67,2
0
IX 30 CX=160:CY=86:X=0:Y=0:DX=6:DY=5:T=1
EC 40 IF T=1 THEN COLOR 1:PLOT 100,40:DRA
WTO 219,40:DRAWTO 219,151:DRAWTO 100,1
51:DRAWTO 100,40
BS 50 COLOR (T=1)
JZ 60 XX=CX+X:YY=CY+Y:GOSUS 1000
LI 70 XX=CX+X:YY=CY-Y:GOSUB 1000
KT 80 XX=CX-X:YY=CY+Y:GOSUB 1000
MC 90 XX=CX-X:YY=CY-Y:GOSUB 1000
BZ 100 IF T=-1 THEN GOSUB 200
FK 110 IF T=1 AND (X=0 OR Y=0) THEN FOR A
=50 TO 0 STEP -1:SOUND 0,A,12,A/3.23:F
OR B=1 TO 10:NEXT B:NEXT A
DV 120 IF T=1 THEN GOSUB 250
II 130 T=-T:GOTO 40
PT 200 X=X+DX:Y=Y+DY:RETURN
MM 250 IF ABS(Y)>53 THEN DY=-DY:GOSUB 300
LV 260 IF ABS(X)>83 THEN DX=-DX:GOSUB 300
ZM 270 RETURN
AF 300 FOR A=15 TO 0 STEP -0.2:SOUND 0,41
,12,A:NEXT A:RETURN
SM 1000 PLOT XX-5,YY-10:DRAWTO XX+5,YY-10
:DRAWTO XX+5,YY:DRAWTO XX-5,YY:DRAWTO
XX-5,YY-10:REM DRAW HEAD
VZ 1010 PLOT XX,YY:DRAWTO XX,YY+20:DRAWTO
XX-7,YY+29:PLOT XX,YY+20:DRAWTO XX+7,
YY+29:REM DRAW BODY AND LEGS
TB 1020 PLOT XX-6,YY+9:DRAWTO XX,YY+7:DRA
WTO XX+6,YY+9:REM DRAW ARMS
AI 1030 RETURN
LISTING 5: ASSEMBLY
10 ;Page flipping routine. After using
20 ;GR.24, GR.9-11, call this routine
30 ;with X=USR(1536) to toggle
40 ;background and foreground page.
50 ;Background page is the one that
60 ;PLOT and DRAWTO effect, and
70 ;foreground is the one that is
75 ;displayed.
80 ;
90 *= $0600
0100 MEMTOP = $02E5 Men top pointer.
0110 SAVMSC = $58 Video men pointer
0120 SDLSTL = $0230 Start of DL.
0130 DLPNTI = $CB Two unused words
0140 DLPNT2 = $CD in zero page.
0150 LDY #0
0160 CLC
0170 LDA SDLSTL Find the
0180 ADC #5 two
0190 STA DLPNT1 display
0200 LDA SDLSTL+1 list
0210 ADC #0 references
0220 STA DLPNT1+1 to video
0230 LDA DLPNT1 memory
0240 ADC #96 and store
0250 STA DLPNT2 then in
0260 LDA DLPNT1+1 unused
0270 ADC #0 part of
0280 STA DLPNT2+1 page 0.
0290 LDA SDLSTL+1 Find area
0300 SEC to store
0310 SBC #31 screen 2
0320 STA MEMTOP+1 safely.
0330 LDA SAVMSC+1 Insure that
0340 CMP (DLPNTI),Y foreground
0350 BNE NORM and
0360 LDA MEMTOP+1 background
0370 STA SAVMSC+1 are
0380 BNE CLEAR different.
0390 NORM TAX Swap both
0400 LDA (DLPNT1),Y of the
0410 STA SAVMSC+1 foreground
0420 TXA pointers
0430 STA (DLPNT1),Y and
0440 CLC the one
0450 ADC #$0F background
0460 STA (DLPNT2),Y pointer.
0470 CLEAR LDA SAVMSC+1 Set up the
0480 STA SCRPNT+1 indexed
0490 LDA SAVMSC addressing
0500 STA SCRPNT command.
0510 LDA #0 Quickly
0520 LDX #30 clear
0530 LOOP STA 0,Y out
0540 INY 7688 byte
0550 BNE LOOP buffer
0560 INC SCRPNT+1 for the
0570 DEX new
0580 BNE LOOP screen.
0590 PLA Unused parameter
0600 RTS Return.
0610 SCRPNT = LOOP+1
0620 ;The SCRPNT pointer is used to
0630 ;modify code on the fly. This
0640 ;allows us to use Indexed
0650 ;addressing which is faster
0660 ;than Post-indexed indirect
0670 ;addressing in the inside loop.
0680 END
LISTING 6: BASIC
TV 30000 RESTORE 30010:FOR X=1536 TO 1627
:READ Y:POKE X,Y:NEXT X:RETURN
PW 30010 DATA 168,9,24,173,48,2,105,5,133
,203,173,49,2,105,0,133,204,165,203,10
5,96,133,205,165,204,105,0,133
QS 30020 DATA 206,173,49,2,56,233,31,141,
230,2,165,89,209,203,208,7,173,230,2,1
33,89,200,13,170,177,203,133
WW 30030 DATA 89,130,145,203,24,105,15,14
5,205,165,89,141,80,6,165,88,141,79,6,
169,0,162,30,153,80,127,200
WF 30040 DATA 200,250,238,80,6,202,208,24
4,184,96
LISTING 7: BASIC
TM 10 REM Press space bar to set alarms.
SR 20 GRAPHICS 0:SETCOLOR 2,0,0:POSITION
13,8:? "";
FV 30 XFR=100:XMK=90:XHR=70:XMI=90:XSE=90
NV 40 YFR=80:YMK=72:YHR=56:YMI=72:YSE=72:
YDI=34:ALRMB=1645:HALF=0
IG 50 IF PEEK(ALRMB-1)<>80 THEN FOR X=ALR
MB TO ALRMB+19:POKE X,0:NEXT X:POKE AL
RMB-1,80
TI 60 DIM S$(2),T$(2),M$(2),W$(8):SHFT=60
*12*3680:CX=160:CY=95:PIOVER2=1.5708:G
OSUB 670:GRAPHICS 0:SETCOLOR 2,0,0
SQ 70 CLOSE #4:OPEN #4,12,0,"K:"
MX 80 ? "Is the clock already set? (Y/N)"
:? "(Or press H for HELP.)";
FS 90 GET A#4,A:IF A=89 THEN GOSUB 1480:GO
TO 260
QW 100 IF A=72 THEN GOSUB 1360:GOTO 80
XQ 110 IF A<>78 THEN 90
CQ 120 ? "N"
GZ 130 TRAP 140:? :PRINT "Is it (A)M or (
P) M?";
GX 140 GET #4,A:IF A=65 THEN S$="AM":GOTO
170
FE 150 IF A=80 THEN S$="PM":GOTO 170
NK 160 GOTO 140
DY 170 ? CHR$CA)
YM 180 TRAP 180:PRINT " What is the hour
";:INPUT H
TF 190 TRAP 190:PRINT " How many minutes
";:INPUT M
WI 200 TRAP 208:PRINT " How many seconds
";:INPUT S
IT 210 TRAP 0:GOSUB 1480
CY 220 JIF=60*(S+60*M+3600*H):IF H<>12 AN
D S$="PM" THEN JIF=JIF+SHFT
KN 230 IF H=12 AND S$="AM" THEN JIF=JIF+S
HFT
GI 240 B18=INT(JIF/65536):JIF=JIF-65536*B
18:B19=INT(JIF/256):B20=JIF-256*B19
MR 250 POKE 20,0:POKE 18,B18:POKE 19,B19:
POKE 20,B20:REM POKE 20,0 INSURES NO T
URNOVERS WHILE SETTING.
RU 260 JIF=(PEEK(18)*65536+PEEK(19)*256+P
EEK(20)):IF JIF>5399999 THEN JIF=JIF-5
184000:GOTO 240
WS 270 JIF=INT(JIF/60)
PF 280 H=JIF/3600:JIF=JIF-3600*INT(H):M=J
IF/60:S=JIF-60*INT(M):IH=INT(H):IM=INT
(M)
ZA 290 H=H/1.9188-PIOVER2:M=M/9.5493-PIOV
ER2:S=S/9.5493-PIOVER2
JX 300 IF PEEK(77)>122 THEN POKE 77,122
ZW 310 SETCOLOR 1,0,15.4-PEEK(77)/10
CI 320 GOSUB 560:REM DRAW CLOCK FRAME
LD 330 PLOT CX,CY:DRAWTO CX+0.7*XHR*COS(H
-0.12),CY+0.7*YHR*SIN(N-0.12):DRAWTO C
X+XHR*COS(H),CY+YHR*SIN(H)
UH 340 DRAWTO CX+0.7*XHR*COS(H+0.12),CY+0
.7*YHR*SIN(H+0.12):DRAWTO CX,CY
ME 350 PLOT CH+1,CY:DRAWTO 1+CX+0.7*XHR*C
OS(H-0.12),CY+0.7*YHR*SIN(H-0.12):DRAW
TO 1+CX+XHR*COS(H),CY+YHR*SIN(H)
FD 360 DRAWTO 1+CX+0.7*XHR*COS(H+0.12),CY
+0.7*YHR*SIN(H+0.12):DRAWTO 1+CM,CY
QG 370 PLOT CX,CY:DRAWTO CX+0.7*XMI*COS(M
-0.07),CY+0.7*YMI*SIN(M-0.07):DRAWTO C
X+XMI*COS(M),CY+YMI*SIN(M)
MM 380 DRAWTO CX+0.7*XMI*COS(M+0.07),CY+0
.7*YMI*SINCM+0.07):DRAWTO CX,CY
TH 390 PLOT CX+1,CY:DRAWTO 1+CX+0.7*XMI*C
OS(M-0.07),CY+0.7*YMI*SIN(M-0.07):DRAW
TO 1+CM+XMI*COS(M),CY+YMI*SIN(M)
XJ 400 DRAWTO 1+CH+0.7*XMI*COS(M+0.07),CY
+0.7*YMI*SIN(M+0.07):DRAWTO 1+CX,CY
ZL 410 REM PLOT CX,CY:DRAWTO CX+XSE*COS(S
),CY+YSE*SIN(S) :REM TOO SLOW!!!
HT 420 REM PLOT CX+1,CY:DRAWTO 1+CX+XSE*C
OS(S),CY+YSE*SIN(S)
TP 430 GOSUS 1240
UL 440 IF PEEK(764)=33 THEN GOSUS 940
JA 450 IF PEEK(764)=28 THEN GRAPHICS 0:GO
SUB 1200:CLR :END
WW 460 POKE 764,255
DI 470 X=USR(1536)
AF 480 IF IM=0 AND HALF=0 THEN GOSUB 760
JR 490 IF IM=1 THEN HALF=0
BD 500 IF IM=30 AND HALF=0 THEN GOSUB 810
JT 510 IF IM=31 THEN HALF=0
EG 520 C=0
NV 530 IF IH=PEEK(ALRMB+2*C) AND IM=PEEK(
ALRMB+2*C+1) THEN GOSUB 890:GOTO 260
GJ 540 C=C+1:IF C<18 THEN 530
OS 550 GOTO 260
BD 560 FOR C=0 TO 11:PLOT X(C),Y(C):DRAWT
O EX(C),EY(C):NEXT C
UT 570 FOR C=0 TO 11:PLOT X(C)+1,Y(C):DRA
WTO EX (C)+1,EY(C):NEXT C
XV 580 FOR C=0 TO 11:PLOT X(C)+2,Y(C):DRA
WTO EX(C)+2,EY(C):NEXT C
AP 590 PLOT PX(11),PY(11):FOR C=0 TO 11:D
RAWTO PX(C),PY(C):NEXT C
QE 600 PLOT PX(11)+2,PY(11):FOR C=0 TO 11
:DRAWTO PX(C)+2,PY(C):NEXT C
NO 610 PLOT PX(11)+1,PY(11):FOR C=0 TO 11
:DRAWTO PX(C)+1,PY(C):NEXT C
RG 620 PLOT PX1(11)+2,PY1(11):FOR C=0 TO
11:DRAWTO PX1(C)+2,PY1(C):NEXT C
OM 630 PLOT PX1(11)+1,PY1(11):FOR C=0 TO
11:DRAWTO PX1(C)+1,PY1(C):NEXT C
XU 640 PLOT PX1(11),PY1(11):FOR C=0 TO 11
:DRAWTO PX1(C),PY1(C):NEXT C
ZK 650 FOR X=0 TO 4:FOR Y=X TO 5:PLOT PX2
(X),PY2(X):DRAWTO PX2(Y),PY2(Y):NEXT Y
:NEXT X
ZO 660 RETURN
XK 670 DIM X(11),Y(11),EX(11),EY(11),PX(1
1),PY(11),PX1(11),PY1(11),PX2(11),PY2(
11):C=0
PP 680 FOR X=0 TO 6.27 STEP 0.5236:X(C)=C
OS(X)*(XMK-2)+CX:EX(C)=COS(X)*(XMK+2)+
CX
TQ 690 Y(C)=SIN(X)*(YMK-2)+CY:EY(C)=SIN(X
*(YMK+2)+CY
NW 700 PX1(C)=COS(X)*XFR*1.1+CX:PY1(C)=SI
N(X)*YFR*1.1+CY
EE 710 PX(C)=COS(X)*XFR+CX:PY(C)=SIN(X)*Y
FR+CY:C=C+1:NEXT X
MZ 720 FOR C=0 TO 5:PX2(C)=COS(C*1.0472)*
XFR/5+CX:PY2(C)=SIN(C*1.0472)*YFR/5+CY
NEXT C
CE 730 IF PEEK(1640)<>96 THEN GOTO 30000
ZL 740 RETURN
SK 750 REM ROUTINE TO DO HOURLY CHIME
BC 760 HALF=1:GOSUB 850:FOR C=1 TO N:FOR
X=3 TO 15 STEP 4:SOUND 0,100,10,X:SOUN
D 1,50,12,X:SOUND 2,102,10,X:NEXT X
KV 770 FOR X=14 TO 0 STEP -0.3:SOUND 0,10
0,10,X:SOUND 1,50,12,X:SOUND 2,102,10,
X:NEXT X
SJ 780 FOR X=1 TO 200:NEXT X:NEXT C
ZV 790 RETURN
PL 800 REM ROUTINE TO DO HALF HOUR CHIME
RL 810 HALF=1:GOSUB 850:FOR X=10 TO 3 STE
P -1:FOR C=0 TO 1:SOUND C,100+C,10,X:N
EXT C:NEXT X
ZB 820 FOR X=10 TO 0 STEP -1:FOR C=0 TO 3
:SOUND C,100+C,10,X:NEXT C:FOR C=1 TO
25:NEXT C:NEXT X
ZK 830 RETURN
QC 840 REM ROUTINE USED BY HOURLY/HALF HO
UR CHIME FOR BOOKEEPING AND TO SILENCE
CHIMES AT LATE NIGHT.
JV 850 IF IH<8 OR IH>22 THEN POP :RETURN
:REM QUIET MODE FROM 11PM TO 7:59AM
QH 860 N=IH:IF IH>12 THEN N=IH-12
ZS 870 RETURN
YB 880 REM ALARM SOUND ROUTINE
QP 890 POKE 764,255:U=30:SETCOLOR 1,0,15:
POKE 77,0
RV 900 FOR X=1 TO 23:FOR Y=0 TO 255 STEP
3:SOUND 0,Y,10,15:SOUND 1,U,10,15:U=U+
1:IF U>255 THEN U=0
OI 910 IF PEEK(764)=255 THEN NEXT Y:NEXT
X
CH 920 POKE 764,255:SOUND 0,0,0,0:SOUND 1
,0,0,0:RETURN
KX 930 REM ROUTINE TO SET ALARMS. NOTE A
LARMS ARE SET IN MEMORY SO ARE NOT LOS
T BETWEEN RUNS
SM 940 GRAPHICS 0:SETCOLOR 2,0,0:FOR X=0
TO 9:? CHR$(65+X);"] ";:C=PEEK(ALRMB+2
*X)
TG 950 IF C=0 THEN ? "No alarm set.":NEXT
X:GOTO 970
LC 960 D=PEEK(ALRMB+1+2*X):GOSUB 1140:? C
;":";M$;" ";T$:NEXT X
YN 970 ? :? "Press: X to exit or":? "
A-J to set an alarm"
SJ 980 GET #4,A:IF A=88 THEN GOSUB 1480:R
ETURN
NJ 990 IF A<65 OR A>74 THEN 980
BQ 1000 A=A-65:IF PEEK(ALRMB+2*A)=0 THEN
1030
WT 1010 ? :? "";CHRS(A+193);"
> ";
IK 1020 C=PEEK(ALRMB+2*A):D=PEEK(ALRMB+1+
2*A):GOSUB 1140:? C;":";M$;" ";T$
FF 1030 ? :? :? " Set [";CHR$
(A+65);"] for what hour":? "
(0 to unset alarm)";:INPUT C
TV 1040 IF C=0 THEN POKE ALRMB+2*A,C:GOTO
940
WP 1050 ? "How many minutes after the hou
r";:INPUT D:POKE ALRMB+2*A+1,D
UJ 1060 PRINT " (A)M or
(P)M?";
TV 1070 GET #4,X:IF X=65 THEN T$="AM":GOT
O 1100
QQ 1080 IF X=80 THEN T$="PM":GOTO 1100
RC 1090 GOTO 1070
IJ 1100 IF C<12 AND T$="PM" THEN C=C+12
WE 1110 IF C=12 AND TS="AM" THEN C=C+12
RJ 1120 POKE ALRMB+2*A,C:GOTO 940
KD 1130 REM TO CONVERT C(HR) AND D(MIN) T
O PRINTABLE FORMS C;M$;T$
VF 1140 T$="PM":IF C<12 OR C=24 THEN T$="
AM"
HR 1150 IF C>12 THEN C=C-12
IY 1160 IF D<10 THEN M$="0":M$(2)=STRS(D)
:GOTO 1180
EK 1170 M$=STR$(D)
AZ 1180 RETURN
ZF 1190 REM ROUTINE TO SHOW CURRENT TIME
VAUES. USEFUL FOR TIMING SOMETHING.
IY 1200 JIF=PEEK(18)*65536*PEEK(19)*256+P
EEK(20):? "JIFFIES = ";JIF:JIF=INT(JIF
/60):? "SECONDS = ";JIF
LY 1210 C=INT(JIF/3600):JIF=JIF-3600*C:D=
INT(JIF/60):S=JIF-60*D:GOSUB 1140:? "T
IME IS> ";C;":";M$;":";S;" ";T$
AJ 1220 RETURN
QA 1230 REM PRINT TIME IN DIGITAL FORM TO
O
TN 1240 WID=36
EB 1250 COLOR 0:FOR X=CY+YDI+1 TO CY+YDI+
10:PLOT CX-WID,X:DRAWTO CX+WID,X:NEXT
X
BS 1260 COLOR 1:FOR X=CY+YDI TO CY+YDI+11
STEP 11:PLOT CX-WID,X:DRAWTO CX+WID,X
:NEXT X
EJ 1270 FOR X=0 TO 1:PLOT CX-WID+X,CY+YDI
:DRAWTO CX-WID+X,CY+YDI+11:NEXT X
YS 1280 FOR X=0 TO 1:PLOT CX+WID+X,CY+YDI
:DRAWTO CX+WID+X,CY+YDI+11:NEXT X
AI 1290 C=IH:D=IM:GOSUS 1140:W$=STR$(C):I
F C<10 THEN W$=" ":W$(2)=STR$(C)
PI 1300 W$(3)=":":W$(4)=MS:W$(6)=" "
GU 1310 W$(7)=T$:Y=CY+YDI+2:X=CX-WID:GOSU
B 1330:RETURN
LL 1320 REM WRITE STRING W$ AT X,Y IN GR.
8
TN 1330 A=40*Y+PEEK(88)+PEEK(89)*256+INT(
(X)/8):BS=256*PEEK(756)
JY 1340 FOR C=1 TO LEN(W$):D=ASC(W$(C,C))
:IF D<95 THEN D=D-32
BS 1350 BT=BS+D*8:FOR CC=BT TO BT+7:POKE
A+C+40*(CC-BT),PEEK(CC):NEXT CC:NEXT C
:RETURN
IS 1360 GRAPHICS 0:SETCOLOR 2,0,0:SETCOLO
R 1,0,10
OD 1370 ? "
"
FX 1380 ? :? ""
ST 1390 ? "Since this clock works off an
internalclock, you will only have to s
et the"
SD 1400 ? "time every time you power up t
he":? "computer. To set the clock jus
t"
QF 1410 ? "answer the questions. To set
the":? "clock accurately, enter the se
conds"
XO 1420 ? "question just as that time pas
ses."
ND 1430 ? :? ""
TD 1440 ? "You can ,set up to 10 alarms.
To set alarms, press the space-bar."
WZ 1450 ? :? ""
UX 1460 ? "To quit the clock just press E
SC."
DN 1470 ? :? :RETURN
YW 1480 GRAPHICS 24:SETCOLOR 2,0,4:SETCOL
OR 4,0,6:COLOR 1:RETURN
TV 30000 RESTORE 30010:FOR X=1536 TO 1627
:READ Y:POKE X,Y:NEXT X:RETURN
PW 30010 DATA 160,0,24,173,48,2,105,5,133
,203,173,49,2,105 0,133,204,165,203,10
5,96,133,205,165,204,105,0,133
QS 30020 DATA 206,173,49,2,56,233,31,141,
230,2,165,89,209,203,208,7,173,230,2,1
33,89,208,13,170,177,203,133
WW 30030 DATA 89,130,145,203,24,105,15,14
5,205,165,89,141,80,6,165,80,141,79,6,
169,0,162,30,153,80,127,200
WF 30040 DATA 208,250,238,80,6,202,208,24
4,104,96
LISTING 8: BASIC
ZK 10 GRAPHICS 0:GOSUB 30000:SETCOLOR 2,0
,0:SETCOLOR 1,0,8
ZI 20 ? "
":? :? "To use program, use joystic
k to move"
BY 30 ? "graphics cursor around. Press t
he":? "fire button to mark points for
the"
SJ 40 ? "program to connect. When you ar
e":? "done, press START. Now, pressin
g the"
EE 50 ? "joystick UP and DOWN will shrink
and":? "expand the picture. Moving t
he"
YZ 60 ? "joystick left and right will mov
e the"
VD 70 ? "picture left and right. Pressin
g the":? "fire button will rotate the
picture":? "10 degrees."
IC 80 ? :? "If you try to move the pictur
e too":? "far left or right or a rotat
ion moves"
IU 90 ? "Part of the picture off the scre
en,":? "the picture automatically shri
nks to":? "fit!"
UF 100 OPEN #3,4,0,"K:":? :? "Press
to begin.":GET #3,A:CLOSE #3
AF 110 CX=160:CV=96:C10=COS(0.17453):S10=
SIN(0.17453)
ZT 120 GRAPHICS 24:COLOR 1:SETCOLOR 2,0,0
AD 130 FOR X=16 TO 319 STEP 16:PLOT X,CY:
DRAWTO X+1,CY:NENT X:FOR Y=12 TO 191 S
TEP 12:PLOT CX,Y:DRAWTO CX+1,Y:NEXT Y
MV 140 DIM A(100),B(100):P=1:X=0:Y=0
JR 150 FOR T=0 TO 1:LOCATE CX+X,CY+Y,Z:CO
LOR (Z=0):PLOT CX+X,CY+Y&:NEXT T
PY 160 A=15-STICK(0):IF A>7 THEN A=A-8:IF
CH+X<318 THEN X=X+1
RN 170 IF A>3 THEN A=A-4:IF CX+X>1 THEN X
=X-1
RR 180 IF A>1 THEN A=A-2:IF CY+Y<190 THEN
Y=Y+1
TG 190 IF A>0 THEN A=A-1:IF CY+Y>1 THEN Y
=Y-1
SU 200 IF STRIG(0)=0 AND P=1 THEN A(1)=X:
B(1)=Y:COLOR 1:PLOT X+CX-1,Y+CY:P=P+1
CC 210 IF STRIG(0)=0 AND P>1 THEN A(P)=X:
B(P)=Y:COLOR 1:PLOT X+CX,Y+CY:DRAWTO A
(P-1)+CX,B(P-1)+CY:P=P+1
UM 220 IF STRIG(0)=0 THEN 220
GJ 230 IF PEEK(53279)=7 THEN 150
ZG 240 IF P<3 THEN ? "You must draw at le
ast 1 line!":END
AE 250 P=P-1:COLOR 1:W=1:S=0
KJ 260 TRAP 350:PLOT S+A(1)*W+CX,B(1)*W+C
Y
NN 270 FOR X=2 TO P:DRAWTO S+A(X)*W+CX,B(
X)*W+CY:NEXT X
DI 280 X=USR(15361
NU 290 IF STICK(0)=13 THEN W=W+0.1:GOTO 2
60
AJ 300 IF STICK(0)=11 AND S>6-CX THEN S=S
-5:GOTO 260
RV 310 IF STICK(0)=7 AND S<CX-6 THEN S=S+
5:GOTO 260
ID 320 IF STICK(0)=14 AND W>0 THEN W=W-0.
1:GOTO 260
OF 330 IF STRIG(0)=0 THEN FOR X=1 TO P:A=
A(X):B=B(X):A(X)=A*C10-B*S10:B(X)=A*S1
0+B*C10:NEXT X:GOTO 260
PV 340 GOTO 290
FL 350 W=W-0.1:GOTO 260
TV 30000 RESTORE 30010:FOR X=1536 TO 1627
:READ Y:POKE X,Y:NEXT X:RETURN
PW 30010 DATA 160,0,24,173,48,2,105,5,133
,203,173,49,2,105,0,133,204,165,203,10
5,96,133,205,165,204,105,0,133
Q5 30020 DATA 206,173,49,2,56,233,31,141,
230,2,165,89,209,203,208,7,173,230,2,1
33,89,208,13,170,177,203,133
WW 30030 DATA 89,138,145,203,24,105,15,14
5,205,165,89,141,80,6,165,88,141,79,6,
169,0,162,30,153,80,127,200
WF 30040 DATA 208,250,238,80,6,202,208,24
4,104,96
LISTING 9: ASSFMBLY
10 ;Page flipping routine. After using
20 ;GR.24, GR.9-11, call this routine
30 ;with X=USR(1664) to copy backgrnd
40 ;to foregrnd page. Backgrnd page
50 ;is the one PLOT and DRAWTO
60 ;effect, and foregrnd is the one
70 ;displayed.
80 ;To clear the whole background
90 ;screen, just do an X=USR(1715)
0100 ;
0110 *= $0680
0120 MEMTOP = $02E5 Men Top pointer.
0130 SAVMSC = $58 Video mem pointer
0140 SDLSTL = $0230 Pointer to DL
0150 LDX SDLSTL+1 Find an
0160 INX area
0170 STX FORPNT+1 to store
0180 TXA background
0190 SEC screen
0200 SBC #32 and set
0210 STA MEMTOP+1 up the
0220 STA SAVMSC+1 indexed
0230 STA BAKPNT+1 addressing
0240 LDA SAVMSC commands
0250 STA BAKPNT for
0260 STA FORPNT copying.
0270 LDY #0 Copy
0280 LDX #30 the
0290 LOOP LDA 0,Y 7680
0300 STA 0,Y byte
0310 INY background
0320 BNE LOOP buffer
0330 INC BAKPNT+1 to
0340 INC FORPNT+1 the
0350 DEX foreground
0360 BNE LOOP screen.
0370 PLA Unused parameter
0380 RTS Return.
0390 CLS LDA SDLSTL+1 Make sure
0400 SEC there's a
0410 SBC #31 background
0420 STA MEMTOP+1 screen.
0430 STA CLSPNT+1 Set
0440 LDA SAVMSC indexed
0450 STA CLSPNT addressing.
0460 LDA #0 Fill
0470 LDX #30 the
0480 LDY #0 7680
0490 LOOP2 STA 0,Y byte
0500 INY background
0510 BNE LOOP2 buffer
0520 INC CLSPNT+1 with
0530 DEX zeroes
0540 BNE LOOP2 (clear).
0550 PLA Pull unused argument.
0560 RTS Return.
0570 CLSPNT = LOOP2+1
0580 BAKPNT = LOOP+1
0590 FORPNT = LOOP+4
0600 .END
LISTING 10: BASIC
TN 31000 RESTORE 31010:FOR X=1664 TO 1751
:READ Y:POKE X,Y:NEXT X:RETURN
BF 31010 DATA 174,49,2,232,142,164,6,138,
56,233,32,141,230,2,133,89,141,161,6,1
65,88,141,160,6,141,163,6
ZY 31020 DATA 160,0,162,30,185,80,127,153
,80,159,200,208,247,238,161,6,238,164,
6,202,208,238,104,96,173,49
EA 31030 DATA 2,56,233,31,141,230,2,141,2
04,6,165,88,141,203,6,169,0,162,30,160
,0,153,80,127,200,208,250
UY 31040 DATA 238,204,6,202,208,244,104,9
6