I feel like painting today. Let’s paint!
Oh, uh, but first…
The Silent Enigma
The Silent Enigma is a new demo by Gurce, based on the song by Anathema. Gurce wrote the demo in BASIC 65 with the Eleven IDE, with assembly language helper routines in Mega Assembler and Acme, and an extended version of grim-fandango’s MEGAPLOT library.
The current version of the demo requires customized versions of the MEGA65 core and ROM to run on MEGA65 hardware. Gurce discovered a need for a new feature of the KERNAL for combining BASIC and machine code routines, and also discovered a core bug while getting it to work. We’re working on getting these improvements into the core platform. In the meantime, Gurce is distributing modified core and ROM files with the demo.
Check out retroComb’s video debuting The Silent Enigma, along with an interview with Gurce. And don’t miss the Eleven and assembly language source files included on the disk!
My talk at PaCommEx NW is online
My talk about the MEGA65 at Pacific Commodore Expo Northwest 2024, Lessons from My First Two Years with the MEGA65, is now on YouTube. My thanks to Robert Bernardo for producing the event, to Stephen Jones and SDF.org for sponsoring, and to everyone who attended. We had three MEGA65s on the floor this year, including a live unboxing of a freshly delivered unit!
C64 core v5.1 released
The C64 core for the MEGA65, one of the best things you can do for your favorite computer, has a new update. Version 5.1 adds support for the R6 mainboard, the board in all MEGA65s being delivered this year, and can take advantage of the R6 board’s bidirectional expansion port lines for Kung Fu Flash, MSSIAH, and freezer cartridge support. This update also includes improvements for all mainboards, including the ability to share the MEGA65’s Real-Time Clock with GEOS, using an appropriate driver.
Don’t forget that the MEGA65 has a new feature that can select the C64 core automatically when a C64 cartridge is installed. If your MEGA65 was delivered this year, your firmware is already up to date with this feature. If you have an older MEGA65, you can update to the v0.96 release in “slot 0” to get this feature. See the User’s Guide, 2nd edition, for upgrade instructions.
See the C64 core release notes for details on all of the changes.
retroCombs MEGA65 Video User’s Guide
retroCombs is producing a video series based on the MEGA65 User’s Guide, 2nd edition. Steven is going chapter by chapter, reviewing the material, and presenting it in an entertaining and easy-to-understand fashion. It’s the perfect video companion to the Guide, and a useful resource in its own right, with additional tips not mentioned in the book. Steven just released the video for chapter 4, and intends to complete the series for the entire book.
Subscribe to retroCombs to make sure you don’t miss a video!
Canvas
I need a canvas to paint on. Something 320 pixels wide and 200 pixels tall is good enough to start. I just want to use the 32 built-in colors for now, so a bit depth of 5 is plenty. (Five binary bits can express up to 32 values: 2 x 2 x 2 x 2 x 2 = 32.) I’ll use screen number 0.
SCREEN 0,320,200,5
Yes, that’s fine. I can’t see what I’m typing now because the text is behind the painting, but I can hold Run/Stop and tap Restore to get back to the text screen.
Blank canvases are intimidating. Whenever I buy a new notebook, I always scribble nonsense on the first page, so I’m not afraid to make mistakes on the other pages. I’ll take a swipe with some white paint (color 1).
PEN 1
LINE 20,30,300,180
I can specify locations on the canvas using numbers, one for the distance in pixels across from the left (the X coordinate), and one for the distance down from the top (the Y coordinate). With a 320 x 200 screen, coordinate X=0 Y=0 is the top-left corner, and X=319 Y=199 is the bottom-right corner. I drew my line from the position X=20 Y=30 to X=300 Y=180.
The 32 colors of the built-in palette are listed in the MEGA65 User’s Guide, 2nd edition, appendix E. The first 16 of these are also written on the fronts of the number keys on the keyboard from 1 to 8, in two rows: colors 0 through 7 are the top row (“Blk” through “Yel”), and colors 8 through 15 are the bottom row (“Orng” through “L Gry”).
I need to switch back to the canvas to see my white line. I’ll set my screen 0 to be both the canvas I’m drawing on and the canvas I’m looking at.
SCREEN SET 0,0
I notice that typing SCREEN 0,320,200,5
again will not switch back to the existing canvas, it’ll open a new blank one. Here’s a way to clear an already-opened canvas, by filling it with color #6 (blue):
SCREEN CLR 6
Flipping back and forth between the text screen and the canvas is a bit cumbersome. I think I’ll put all of my painting commands into a BASIC program. This way, the MEGA65 can recreate my picture by following my painting instructions, and I can save my program to a floppy disk.
10 SCREEN 0,320,200,5
20 PEN 1
30 LINE 20,30,300,170
DSAVE "LINE"
RUN
I can press Run/Stop + Restore to get back to text mode, make changes to the program, and RUN
it again to see the result.
If I wanted to give this program to someone else, they might enjoy being able to exit back to text mode by pressing a key. Here’s a simple way to do that:
9998 GETKEY A$
9999 SCREEN CLOSE 0
In addition to lines, BASIC has commands for drawing dots, and drawing shapes of several kinds, both filled and unfilled. I’m just messing around, changing the numbers to see how they change the picture.
40 PEN 2
50 DOT 4,4
60 DOT 5,5
70 DOT 6,4
80 DOT 7,5
90 DOT 8,4
100 PEN 3
110 BOX 180,10,240,50
120 BOX 200,30,260,70,1
130 PEN 4
140 CIRCLE 50,150,24
150 CIRCLE 70,130,24,1
160 PEN 5
170 ELLIPSE 180,150,50,20
180 ELLIPSE 160,130,50,20,1
190 PEN 6
200 POLYGON 250,100,40,40,5
210 POLYGON 270,120,40,40,5,,,,1
Of course, the User’s Guide has more information on how these commands work, including some additional interesting features.
Here is a simple picture I made.
5 BORDER 0
10 SCREEN 0,320,200,5
20 PEN 27:BOX 0,0,319,30,1
30 PEN 28:BOX 0,31,319,60,1
40 PEN 29:BOX 0,61,319,90,1
50 PEN 30:BOX 0,91,319,120,1
60 PEN 0:CIRCLE 220,280,200,1
70 BOX 200,60,240,60,230,90,210,90,1
80 BOX 200,48,240,48,250,60,190,60,1
90 BOX 210,42,213,42,213,48,210,48,1
100 PEN 7:BOX 222,65,227,65,226,72,223,72,1
110 PEN 11:CIRCLE 213,36,4,1
120 CIRCLE 223,33,3,1
130 CIRCLE 232,31,4,1
Computer art
Wherever there’s a number in a computer program, there could also be some computation that produces a number. This can turn math formulas, variables, and flow control structures into their own kind of computational paintbrush.
I want to try a simple grid pattern with regularly spaced lines. Instead of writing out all of the coordinates for each line, I’ll have the MEGA65 figure it out for me.
5 BORDER 0
10 SCREEN 0,320,200,5
20 PEN 1
30 FOR X=0 TO 319 STEP 20
40 LINE X,0,X,199
50 NEXT X
60 FOR Y=0 TO 199 STEP 20
70 LINE 0,Y,319,Y
80 NEXT Y
I can tell the computer how to calculate a number. Or, I can just let the computer pick a number at random. The computer can use its own imagination to paint a picture, in accordance with my instructions. (well actually computers don’t have imaginations and random numbers aren’t really random and whatever it’s fun)
5 BORDER 0
10 SCREEN 0,320,200,5
20 PEN RND(1)*32
30 LINE RND(1)*320,RND(1)*200,RND(1)*320,RND(1)*200
40 GOTO 20
BASIC 65 has some mathematical functions that can help paint interesting pictures, if I can remember enough geometry.
5 BORDER 0
10 SCREEN 0,320,200,5
20 FOR Z=0 TO 4
30 PEN RND(1)*32
40 R=RND(1)*40+20
50 CX=RND(1)*200+60
60 CY=RND(1)*80+60
70 FOR A=0 TO 2*π STEP 2*π/30
80 LINE CX,CY,CX+COS(A)*R,CY+SIN(A)*R
90 NEXT A
100 NEXT Z
Those symbols on line 70 are the Greek letter pi (π), which I typed with Shift + up-arrow. In BASIC 65, this is the geometric constant pi, defined as the circumference of a circle divided by its diameter. Someone check my math.
Graphing calculator
I keep my MEGA65 on my desk and sometimes just use it as a simple calculator, typing a question mark ?
followed by an arithmetic expression at the READY.
prompt to get a quick answer. I wonder if I could make the MEGA65 into a graphing calculator.
1 DEF FN Y(X) = SIN(X*9)+1.5
2 XL = -3 : XH = 3
3 YL = -1 : YH = 4
4 REM ======================
5 BORDER 0
10 SCREEN 0,320,200,5
20 REM ==== DRAW AXES
30 PEN 12
40 IF 0 < XL OR XH < 0 THEN 70
50 V = 0:L = XL:H = XH:SC = 320:GOSUB 1000:XC = C
60 LINE XC,0,XC,199
70 IF 0 < YL OR YH < 0 THEN 100
80 V = 0:L = YL:H = YH:SC = 200:GOSUB 1000:YC = 199-C
90 LINE 0,YC,319,YC
94 IF XC > 351 THEN XC = 351
95 IF YC > 192 THEN YC = 192
100 CHAR 0,YC+1,1,1,2,STR$(XL)
110 CHAR 39-LEN(STR$(XH)),YC+1,1,1,2,STR$(XH)
120 CHAR XC/8+1,0,1,1,2,STR$(YH)
130 CHAR XC/8+1,191,1,1,2,STR$(YL)
140 REM ==== DRAW FUNCTION
150 PEN 7
160 PX = 0
170 V = FN Y(XL):L = YL:H = YH:SC = 200:GOSUB 1000:PY = SC-C
180 FOR X = XL TO XH STEP (XH-XL)/160
190 V = X:L = XL:H = XH:SC = 320:GOSUB 1000:NX = C
200 V = FN Y(X):L = YL:H = YH:SC = 200:GOSUB 1000:NY = SC-C
210 LINE PX,PY,NX,NY
220 PX = NX : PY = NY
230 NEXT X
999 END
1000 REM ==== SCALE V TO C WITHIN RANGE (L,H) BY SC
1010 C = (V-L)/(H-L)*SC
1020 IF C > SC THEN C = SC
1030 IF C < 0 THEN C = 0
1040 RETURN
Huh… That’s interesting…
I think I got the gist of this right. The first few lines define the function to be plotted, and the domain (XL
to XH
) and range (YL
to YH
) to use for the graph.
The subroutine starting on line 1000 scales a value V
to screen coordinate C
within value range (L
,H
) scaled by SC
. For example, to convert an X value to a horizontal screen coordinate, I set V
to the X value, L
to XL
, H
to XH
, and SC
to 320 (the pixel width of the screen). The subroutine returns with C
set to the horizontal screen coordinate.
190 V = X:L = XL:H = XH:SC = 320:GOSUB 1000:NX = C
I use this subroutine for every such conversion. Importantly, I need to invert the vertical coordinate that comes back from this, because math graphs go up as Y values increase, but screen coordinates go down. So PX = C
, and PY = SC-C
.
To keep this simple, I only draw a zero-axis if the zero is within the range/domain, and I don’t bother with tick marks. I use the CHAR
command to print the range/domain values close to the zero-axis lines, if appropriate, making sure they stay on screen.
To draw the function itself, I calculate a starting point based on its value for the leftmost point on the screen, FN Y(XL)
, then loop over 160 evenly spaced points between XL
and XH
. For each iteration, I draw a line from the previous point to the next. PX
/NX
and PY
/NY
are the previous and next horizontal and vertical screen coordinates.
Real graphing calculators are pretty sophisticated. They need to be to produce something useful under all circumstances. For example, I just allow a graph that goes off the top or bottom of the screen to squash up against the edge. The LINE
command doesn’t mind receiving fractional coordinates, but it will complain if I give it values outside of the screen. This could be improved by calculating exactly where the graph crosses the edge. But I’m painting here, not building something useful.
Also my sine graphs have a bit of a cowlick in some spots, for some reason. I’m guessing this is hitting up against the range limits of BASIC 65 floating point numbers. Math is hard. 🤷 Moving on…
Paintbrush
Painting with code is fun, but this computer can do more than use hand-entered numbers or numbers derived from math and randomness. I can also write a program that changes numbers interactively based on keys I press on the keyboard. Here’s the simplest version of this idea:
10 SCREEN 0,320,200,5
20 X=100:Y=100
30 PEN 1
40 DOT X,Y
50 GETKEY A$
60 IF A$=CHR$(17) AND Y<199 THEN Y=Y+1
70 IF A$=CHR$(29) AND X<319 THEN X=X+1
80 IF A$=CHR$(145) AND Y>0 THEN Y=Y-1
90 IF A$=CHR$(157) AND X>0 THEN X=X-1
100 GOTO 40
This operates similarly to our Robot Finds Kitten experiment from a while back. The program maintains a cursor position in the X and Y variables. It waits for a keypress, then compares it to the PETSCII codes for the cursor keys. After it confirms the cursor position won’t leave the screen, it changes the cursor position, then draws a dot. I can move the dot around the screen, and it leaves a trail, like an Etch-a-Sketch.
I could also make this controllable with a joystick, with almost no changes:
10 SCREEN 0,320,200,5
20 X=100:Y=100
30 PEN 1
40 J=JOY(2)
50 DOT X,Y
60 IF J=5 AND Y<199 THEN Y=Y+1
70 IF J=3 AND X<319 THEN X=X+1
80 IF J=1 AND Y>0 THEN Y=Y-1
90 IF J=7 AND X>0 THEN X=X-1
100 GOTO 40
Whoa! Uh, slow down there, partner:
55 SLEEP 0.01
This only supports four directions of movement, and actually feels like it sticks when I accidentally press the joystick in a diagonal direction. The JOY()
function returns different values for diagonals. (See the User’s Guide.) This should work.
60 IF (J=4 OR J=5 OR J=6) AND Y<199 THEN Y=Y+1
70 IF (J=2 OR J=3 OR J=4) AND X<319 THEN X=X+1
80 IF (J=8 OR J=1 OR J=2) AND Y>0 THEN Y=Y-1
90 IF (J=8 OR J=7 OR J=6) AND X>0 THEN X=X-1
It’d be nice if I had more control over the paintbrush behavior. Maybe if it doesn’t draw unless I press the button?
50 IF J AND 128 THEN DOT X,Y:J=J AND 127
JOY()
returns a value 0 through 8 representing the joystick direction, plus 128 if the fire button is pressed. I’m using a bitwise AND
both to test the button on its own, and to erase the button part of the value for the rest of the comparisons.
OK that works, but now I can’t really see what I’m doing. Before, it was always drawing, so I could usually see where it will draw next when I move. Now it’s only drawing when the button is pressed. I need some kind of cursor on the display that doesn’t draw into the image itself.
On Commodores, that’s what sprites are for. We covered sprites, yeah? I’m just going to use the built-in arrow sprite for now:
15 SPRITE 0,1
45 MOVSPR 0,X+24,Y+50
Remember that the sprite coordinate system is not the same as the screen coordinate system inside the border. The upper corner for a sprite is X=24, Y=50, so I need to add these values to the MOVSPR
command.
That’s pretty good… Looks like there might be a bug in sprite coordinates over bitplanes. We’ll have to look into that.
That arrow cursor reminds me, I could also write this to use the mouse. This simplifies the code quite a bit because the KERNAL does its own range checking on the mouse position. My program just needs to read the mouse position, check for the button press, and draw a dot there if it is pressed. I still need to offset the mouse coordinates when I draw, this time in the other direction because X
and Y
are set to sprite coordinates by the RMOUSE
command.
10 SCREEN 0,320,200,5
20 MOUSE ON,1
30 PEN 1
40 RMOUSE X,Y,B
50 IF B THEN DOT X-24,Y-50
60 GOTO 40
That’s neat! The dots are a bit spread apart though. I wonder if I can combine this with the technique in the graphing calculator to get a smoother line while the button is pressed.
10 SCREEN 0,320,200,5
20 MOUSE ON,1
30 PEN 1
40 PX=-1
50 RMOUSE X,Y,B
60 IF B<>128 THEN PX=-1:GOTO 50
70 X=X-24:Y=Y-50
80 IF PX=-1 THEN 100
90 LINE PX,PY,X,Y
100 PX=X:PY=Y
110 GOTO 50
Hmmm…
41 SPRITE 0,1,1
51 GET A$:IF A$<"1" OR A$>"9" THEN 60
52 PEN VAL(A$)
53 SPRITE 0,1,VAL(A$)
Maybe…
90 CIRCLE X+RND(1)*10-5,Y+RND(1)*10-5,RND(1)*5,1
And what about…
42 SC=1
61 SC=SC-1
62 IF SC>0 THEN 70
63 SOUND 1,RND(1)*65535,5
64 SC=50
Oh, here’s an idea…
90 LINE PX,PY,X,Y
91 LINE 320-PX,PY,320-X,Y
92 LINE PX,200-PY,X,200-Y
93 LINE 320-PX,200-PY,320-X,200-Y
That was fun!
Did I forget to include screenshots of my paintings? Ah, well. I suppose you can always just type these in and see what happens.
If you liked this one, please consider supporting the Digest with a contribution. I hope to continue making more of these, and your support goes a long way to making that possible. Visit: ko-fi.com/dddaaannn
Happy painting! See you next month.
— Dan