ZX Spectrum Raytracer
This is the example output and source code for the 2nd iteration of the ZX Spectrum Raytracer, with better handling of attribute clashes.
1 BRIGHT 1: CLS 5 LET ROX = 0 6 LET ROY = 0 7 LET ROZ = 0 8 LET TMIN = 0 9 LET TMAX = 10000 10 FOR X = 0 TO 255 STEP 8 20 FOR Y = 0 TO 175 STEP 8 30 DIM C(64) 31 LET CI = 1 32 DIM A(8) 120 REM --- For each 8x8 block, collect the pixel colors and their counts --- 125 FOR U = X TO X+7 126 FOR V = Y TO Y+7 130 LET RDX = (U - 128) / 256 131 LET RDY = (V - 88) / 256 132 LET RDZ = 1 140 GO SUB 1000 141 LET C(CI) = COL 142 LET CI = CI + 1 143 LET A(COL+1) = A(COL+1) + 1 160 NEXT V 161 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 FCOL = MFI - 1 207 LET II = MFI: LET MFC = 0: LET MFI = 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 SCOL = MFI - 1 259 REM --- If there's only one color, paint the whole block -- 260 IF SCOL <> -1 THEN GO TO 300 270 POKE 22528 + X/8 + 32*(21-Y/8), 64 + FCOL * 8 280 GO TO 500 300 REM --- Otherwise 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) <> FCOL THEN PLOT INK SCOL; PAPER FCOL; U, V 321 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 1000 REM ===== TraceRay ===== 1001 REM Params: (ROX, ROY, ROZ): ray origin; (RDX, RDY, RDZ): ray direction; (TMIN, TMAX): wanted ranges of t 1002 REM Returns: COL: pixel color 1010 LET COL = -1: LET MINT = 0 1100 RESTORE 9000 1101 READ NS 1102 FOR S = 1 TO NS 1110 READ SCX, SCY, SCZ, SRAD, SCOL 1200 LET COX = ROX - SCX 1201 LET COY = ROY - SCY 1202 LET COZ = ROZ - SCZ 1210 LET EQA = RDX*RDX + RDY*RDY + RDZ*RDZ 1211 LET EQB = 2*(RDX*COX + RDY*COY + RDZ*COZ) 1212 LET EQC = (COX*COX + COY*COY + COZ*COZ) - SRAD*SRAD 1220 LET DISC = EQB*EQB - 4*EQA*EQC 1230 IF DISC < 0 THEN GO TO 1500 1240 LET T1 = (-EQB + SQR(DISC)) / 2*EQA 1241 LET T2 = (-EQB - SQR(DISC)) / 2*EQA 1250 IF T1 >= TMIN AND T1 <= TMAX AND (T1 < MINT OR COL = -1) THEN LET COL = SCOL: LET MINT = T1 1300 IF T2 >= TMIN AND T2 <= TMAX AND (T2 < MINT OR COL = -1) THEN LET COL = SCOL: LET MINT = T2 1500 NEXT S 1999 IF COL = -1 THEN LET COL = 0 2000 RETURN 3000 REM ===== Get timestamp in seconds ===== 3001 LET TIME = (65536*PEEK 23674 + 256*PEEK 23673 + PEEK 23672) / 50 3002 RETURN 8998 REM ===== Sphere data ===== 8999 REM Sphere count, followed by (SCX, SCY, SCZ, SRAD, 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, 6