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
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