Let's paint!

MEGA65 Projects

Let’s paint! Dan’s MEGA65 Digest for July 2024.

Let's paint!
A blank canvas
A blank canvas.

I feel like painting today. Let’s paint!

Oh, uh, but first…

My talk at PaCommEx NW is online

The title slide of my talk at Pacific Commodore Expo Northwest

My talk at Pacific Commodore Expo Northwest

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!

MEGA65 at the Vintage Computer Festival Midwest, September 7-8, 2024

Vintage Computer Festival Midwest, image of the website

Vintage Computer Festival Midwest.

I’m working up plans to be at the Vintage Computer Festival Midwest, September 7-8, 2024, at the Schaumburg Convention Center in Schaumburg, Illinois near Chicago. This large show attracts enthusiasts from all over the USA and Canada, and is a regular pilgrimage for collectors, computer clubs, YouTubers, and makers of modern retro computers and peripherals. Admission is free.

This year, I’ll be collaborating with Jim Happel (jim_64) on a MEGA65 table. I’ve also applied for a speaking slot to deliver a revised version of the “Lessons from…” talk, though those won’t be announced until next month, so, fingers crossed. 🤞

MEGA65 at the Portland Retro Gaming Expo, September 27-29, 2024

The Portland Retro Gaming Expo

The Portland Retro Gaming Expo.

My MEGA65 and I will be at the Portland Retro Gaming Expo, September 27-29, 2024, in Portland, Oregon, USA. PRGE is one of the largest vintage video gaming shows in the Pacific Northwest, and this year they’re doing a home computing exhibition. Come for the interactive volunteer-run computer exhibits, then stay for the weekend of talks, playable arcade games, and the vendor floor. I’m not doing a talk at this one, but I’ll have my own table in the home computing area.

PRGE is a ticketed event at the Oregon Convention Center. If you’re visiting from out of town, get your hotel rooms reserved early—and make sure to leave time to explore Portland!

C64 core v5.1 released

The Commodore 64 core for the MEGA65

The Commodore 64 core for the MEGA65

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 MEGA65 User's Guide video series

retroCombs MEGA65 User’s Guide video series.

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 MEGA65 system palette of 32 colors
The MEGA65 system palette of 32 colors.

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…

A graph of the BASIC 65 sine function (actually a cropped photo of actor Austin Butler
A graph of the BASIC 65 sine function?

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