28 November, 2013

Commodore 64 Mandelbrot, in color!

Thanks to a great post by Semi-Original Thought, I witnessed a Mandelbrot set being rendered on a C64. I hadn't seen this since the 1980s! Back then the fractal inspiration was due to Scientific American magazine (Martin Gardner?), and the school library

Rendering is painfully slow on a real C64, but fortunately the VICE emulator has a Turbo mode; far faster than the original by about 50x.

Two programs were supplied by the Semi-Original Thought post; a lo-res rendering, and another for a 2-color hi-res render. The C64 supports more colors, so I figured I'd drop from the hi-res of 320x200 down to 160x200, which enables multicolor mode. For simplicity, I stuck with 4 colors; with fewer pixels to compute, the render is faster (still a few minutes even in Turbo mode!) 

Drawing very heavily from the Semi-Original Thought code, here's the multi-color version. The main changes are:

  • The POKEing in the graphics section (lines 600-), to handle multi-color. 
  • I added some machine code to speed screen erasing. It takes quite some time for C64 BASIC to clear 8000 bytes. In machine code, it's almost instantaneous. Lines 800- for that clearing code.
  • Since the Mandelbrot set is mirrored about the x-axis, I skip computing the mirrored bottom half and draw 2 pixels for every computation. This also affected lines 600-.



  100 xl =-2.000:xu =0.500
  110 yl =-1.100:yu=1.100
  115 reps =20
  120 width =160:height =200
  130 xinc =(xu -xl)/width
  140 yinc =(yu-yl)/height
  200 rem main routine
  205 print "{clr}"
  207 gosub 500
  210 for j = 0 to int((height - 1)/2)
  220 for i = 0 to width -1
  230 gosub 300
  240 gosub 600
  260 next
  270 next
  290 get a$: if a$ = ""then 290
  299 goto 700
  300 rem calculate mandelbrot
  312 nreal = xl + i * xinc
  313 nimg = yl+j*yinc
  315 rz=0:iz=0
  316 r2z=0:i2z=0
  320 for k = 1 to reps
  330 r2z=rz*rz-iz*iz
  340 i2z=2*rz*iz
  350 rz=r2z+nreal
  360 iz=i2z+nimg
  370 if(rz*rz+iz*iz)>4 goto395
  390 next
  395 if k<7 then c=3:return:rem here we are assigning colors
  396 if k<9 then c=2:return
  397 if k<14then c=1:return
  398 c=0
  400 return
  500 rem clear screen
  530 poke 53272, 29:poke 53265, 59
  531 poke53270,peek(53270)or16
  532 poke 53281, 0
  541 gosub 800
  549 rem set screen colors to grays
  550 for r=1024 to 2023:poke r,207:next
  560 for r=55296to56295:poke r,14:next
  598 return
  599 rem draw hi-res
  600 ch=int(i/4)*8
  605 k=height-1-j : rem here we do the mirroring
  610 p =8192 + int(j/8)*320 + ch+(jand7)
  615 p2=8192 + int(k/8)*320 + ch+(kand7)
  625 lb=2^(7-(1+2*(iand3))):rem multicolor low bit
  626 hb=2^(7-(2*(iand3))): rem high bit
  630 if c=0 then return
  635 a=peek(p)
  640 if c=1 then pokep,a or lb
  641 if c=1 then pokep2,a or lb:return
  650 if c=2 then pokep,a or hb
  651 if c=2 then pokep2,a or hb:return
  655 a=a or lb
  660 pokep,a
  661 pokep2,a
  670 pokep, a or hb
  671 pokep2, a or hb
  680 return
  700 rem return to normal
  705 poke 53280, 14:poke 53281,6
  740 poke 53272,21:poke 53265,27
  750 poke 53270,peek(53270)and239
  760 end
  799 rem some machine code to erase the hires screen
  800 for i= 0to 20:read a:poke 49152+i, a:next
  810 data 169,0,162,32,160,0,132,33,134,34,145,33,200,208,251,232,224,64,208,244
  815 data 96
  820 sys49152
  830 return


1 comment:

  1. This is so awesome!!! Thanks so much for making this, and sorry it took so long for me to see it. I took a little break from blogging.

    ReplyDelete