# ZX Spectrum Raytracer

This is the example output and source code for the 3rd iteration of the ZX Spectrum Raytracer, with performance improvements.

1 BRIGHT 1: CLS 3 LET DX = 0: LET DY = 0: LET DZ = 1: GO SUB 1000: REM The order of declaration of variables makes the program faster (!) 4 DIM C(64) 20 FOR X = 0 TO 255 STEP 8 25 FOR Y = 0 TO 175 STEP 8 39 REM --- Fast approximate path: if all 4 corners of this 8x8 block are the same color, draw the whole block with that color --- 40 LET DX = (X - 128) / 256: LET DY = (Y - 88) / 256: GO SUB 1000: LET CTL = COL 41 LET DX = (X - 128 + 7) / 256: GO SUB 1000: LET CTR = COL 42 LET DY = (Y - 88 + 7) / 256: GO SUB 1000: LET CBR = COL 43 LET DX = (X - 128) / 256: GO SUB 1000: LET CBL = COL 50 IF CTL = CBR AND CTL = CTR AND CTL = CBL THEN POKE 23200 + X/8 - 4*Y, 64 + COL*8: GO TO 500 100 REM --- For each 8x8 block, collect the pixel colors and their counts --- 111 LET CI = 1 112 DIM A(8) 125 FOR U = X TO X+7 126 LET DX = (U - 128) / 256 130 FOR V = Y TO Y+7 140 IF CI = 1 THEN LET COL = CTL: GO TO 160 141 IF CI = 8 THEN LET COL = CBL: GO TO 160 142 IF CI = 57 THEN LET COL = CTR: GO TO 160 143 IF CI = 64 THEN LET COL = CBR: GO TO 160 150 LET DY = (V - 88) / 256 151 GO SUB 1000 160 LET A(COL+1) = A(COL+1) + 1 161 LET C(CI) = COL 162 LET CI = CI + 1 170 NEXT V 171 NEXT U 199 REM --- Find the most and second most frequent colors in this 8x8 block --- 201 LET MFC = 0 202 FOR C = 1 TO 8 203 IF A(C) > MFC THEN LET MFC = A(C): LET MFI = C 204 NEXT C 205 LET FC = MFI - 1 207 LET II = MFI: LET MFC = 0 208 FOR C = 1 TO 8 209 IF C <> II AND A(C) > MFC THEN LET MFC = A(C): LET MFI = C 210 NEXT C 211 LET SC = MFI - 1 300 REM --- Set the PAPER to the most frequent color, and draw everything else in the second most frequent color -- 301 LET CI = 1 310 FOR U = X TO X+7 311 FOR V = Y TO Y+7 320 IF C(CI) <> FC THEN PLOT INK SC; PAPER FC; U, V 325 LET CI = CI + 1 350 NEXT V 351 NEXT U 500 NEXT Y 505 GO SUB 3000: PRINT AT 0, 0; TIME 510 NEXT X 520 STOP 990 REM ===== TraceRay ===== 991 REM Params: (DX, DY, DZ): ray direction 992 REM Returns: COL: pixel color 993 REM Optimizations: ray origin hardcoded to (0, 0, 0); (TMIN, TMAX) hardcoded to (0, +inf) 1000 LET MT = 1E10 1020 LET A = 2*(DX*DX + DY*DY + DZ*DZ) 1100 RESTORE 9000 1101 READ NS 1102 FOR S = 1 TO NS 1110 READ CX, CY, CZ, SR, SC 1211 LET B = 2*(DX*CX + DY*CY + DZ*CZ) 1212 LET C = (CX*CX + CY*CY + CZ*CZ) - SR 1220 LET D = B*B - 2*A*C 1230 IF D < 0 THEN GO TO 1500 1231 LET D = SQR(D) 1240 LET T = (B + D) / A 1241 IF T > 0 AND T < MT THEN LET COL = SC: LET MT = T 1250 LET T = (B - D) / A 1251 IF T > 0 AND T < MT THEN LET COL = SC: LET MT = T 1500 NEXT S 1999 IF MT = 1E10 THEN LET COL = 0 2000 RETURN 2999 REM ===== Get timestamp in seconds ===== 3000 LET TIME = (65536*PEEK 23674 + 256*PEEK 23673 + PEEK 23672) / 50 3001 RETURN 8998 REM ===== Sphere data ===== 8999 REM Sphere count, followed by (CX, CY, CZ, RADIUS*RADIUS, COLOR) 9000 DATA 4 9001 DATA 0, -1, 4, 1, 2 9002 DATA 2, 0, 4, 1, 1 9003 DATA -2, 0, 4, 1, 4 9004 DATA 0, -5001, 0, 5000^2, 6