%TRUE EQU 1 %FALSE EQU 0 REM constants pi EQU 3.1415926536 twopi EQU 2*pi piby2 EQU pi/2 REM perspective parameters p1 EQU 600 :REM ** p1 is scaling factor p2 EQU 300 :REM ** p2 is distance from origin REM ** Half Screen Size xo EQU 320 yo EQU 240 l EQU 0 m EQU 0 n EQU 0 i EQU 0 j EQU 0 k EQU 0 depth EQU 80 REM ** number of +/- squares nx EQU 7 nz EQU 7 REM ** length of squares dx EQU 50 dz EQU 50 REM ** rotation of chessboard about Y axis alpha EQU 30*pi/180 REM ** light source position sx EQU 50 sy EQU -100 sz EQU -90 REM ** scaling factor for other calculations f EQU 100 lx EQU sx*f ly EQU sy*f lz EQU sz*f REM Sphere radius radii EQU 99 REM Sphere origin originx EQU 0 originy EQU -50 originz EQU 30 REM ********** Main Program ********** CALL setcolours CALL drawchessboard(0,alpha,0) CALL shadow(radii,originx,originy,originz) CALL sphere(radii,originx,originy,originz) CALL die REM ********* Subroutines ********** drawchessboard PROC NEAR ;drawchessboard (a,b,c) SHARED dx,dz,i,j,k,nx,nz,Depth,p1,p2 LOCAL i1,j1,k1,v1x,v1y,v1z,v2x,v2y,v2z,v3x,v3y,v3z,v4x,v4y,v4z,x,z,COL ; FOR x=-nx TO nx STEP 1 MOV AX,-nx CMP AX,nx+1 JZ doneboard xloop ; FOR z = nz to -nz STEP -1 MOV CX,nz CMP CX,-nz-1 JZ doneloop zloop i1=x*dx j1=depth k1=z*dz v1x=i1 v1y=j1 v1z=k1 v2x=i1 v2y=j1 v2z=k1-dz v3x=i1-dx v3y=j1 v3z=k1 v4x=i1-dx v4y=j1 v4z=k1-dz CALL rot(a,b,c,v1x,v1y,v1z) v1x=i:v1y=j:v1z=k CALL rot(a,b,c,v2x,v2y,v2z) v2x=i:v2y=j:v2z=k CALL rot(a,b,c,v3x,v3y,v3z) v3x=i:v3y=j:v3z=k CALL rot(a,b,c,v4x,v4y,v4z) v4x=i:v4y=j:v4z=k v1x=p2*v1x/(v1z+p1) v1y=p2*v1y/(v1z+p1) v2x=p2*v2x/(v2z+p1) v2y=p2*v2y/(v2z+p1) v3x=p2*v3x/(v3z+p1) v3y=p2*v3y/(v3z+p1) v4x=p2*v4x/(v4z+p1) v4y=p2*v4y/(v4z+p1) COL=11-5*((X AND 1) XOR (Z AND 1)) CALL Quad(COL,V1X,V1Y,V2X,V2Y,V3X,V3Y,V4X,V4Y) NEXT Z NEXT X END SUB SUB Sphere(R,ox,oy,oz) LOCAL I,J,K,Y,da,dy,radius,C1,C2,COL,angl SHARED l,m,n,lx,ly,lz,pi,twopi dy=0.5 da=0.5*pi/180 FOR Y=-R to R STEP dy IF Y<>0 THEN Radius=SQR(R*R-Y*Y) J=Y+oy FOR angl=0 TO twopi STEP da I=Radius*COS(angl)+ox K=Radius*SIN(angl)+oz IF FNVisible(I,J,K,ox,oy,oz,0,0,-2000)=%TRUE THEN CALL TraceRay(I,J,K,ox,oy,oz) C1=FNLightSource(I,J,K,ox,oy,oz) C2=FNColourComponent(R,I,J,K,ox,oy,oz) IF C1=-1 THEN CALL Plot(I,J,K,1) ELSE CALL Plot(I,J,K,C1+C2) END IF NEXT angl END IF NEXT Y END SUB SUB Shadow(R,ox,oy,oz) LOCAL C,Y,I1,J1,K1,da,dy,radius,angl SHARED Alpha,i,j,k,l,m,n,lx,ly,lz,dx,dz,nx,nz,pi,twopi dy=2 da=pi/180 FOR Y=-R TO R STEP dy IF Y=0 THEN EXIT FOR Radius=SQR(R*R-Y*Y) J1=Y+oy FOR angl=0 TO twopi STEP da I1=Radius*COS(angl)+ox K1=Radius*SIN(angl)+oz CALL TraceRay(I1,J1,K1,x,ly,lz) CALL Rot(0,-Alpha,0,l,m,n) u=i:v=j:w=k IF (ABS(u)0 THEN answer=%TRUE ELSE answer=%FALSE FNVisible=answer END DEF DEF FNLightSource(X,Y,Z,OX,OY,OZ) LOCAL answer,I,J,K,da,Vx,Vy,Vz,Ml,Mp,lp,angle,sp SHARED Sx,Sy,Sz,pi Vx=Sx-OX Vy=Sy-OY Vz=Sz-OZ I=X-OX J=Y-OY K=Z-OZ sp=Vx*I+Vy*J+Vz*K Ml=SQR(Vx*Vx+Vy*Vy+Vz*Vz) Mp=SQR(I*I+J*J+K*K) lp=Ml*Mp angle=FNArccos(sp/lp) da=5*pi/180 IF angle<0 THEN CALL CRASH("Light source error - source touches sphere?",angle*180/pi) 'IF (angle>=0) AND (angle=da) AND (angle<2*da) THEN answer=3 'IF (angle>=2*da) AND (angle<3*da) THEN answer=2 'IF (angle>=3*da) AND (angle<4*da) THEN answer=1 'IF (angle>=4*da) THEN answer=0 answer=4-FIX(angle/da) IF answer<0 THEN answer=0 IF answer=4 THEN answer=-1 FNLightSource=answer END DEF DEF FNColourComponent(R,X,Y,Z,OX,OY,OZ) LOCAL I1,J1,K1,u,v,w,C,Pdist SHARED Alpha,l,m,n,i,j,k,dx,dz,nx,nz,lx,ly,lz I1=X-OX J1=Y-OY K1=Z-OZ REM ** Ray hits sky! IF J1<0 THEN FNColourComponent=2 EXIT DEF END IF rem ** ray beyond chessboard? CALL Rot(0,-Alpha,0,l,m,n) u=i:v=j:w=k IF (ABS(u)>dx*nx) OR (ABS(w)>dz*nz) THEN FNColourComponent=2 EXIT DEF END IF rem ** does ray hit shadow? Pdist=FNReflect(OX,OY,OZ,lx,ly,lz,l,m,n) IF Pdist1 THEN CALL CRASH("Arcosine Error",a) ELSE x=-a/SQR(1-a*a) FNArccos=piby2+ATN(x) EXIT DEF END IF END DEF DEF FNArcSin(a) SHARED piby2 IF a=1 THEN FNArcSin=piby2 EXIT DEF ELSEIF a=-1 THEN FNArcSin=-piby2 EXIT DEF ELSEIF ABS(a)>1 THEN CALL CRASH("Arcsine Error",a) ELSE x=a/SQR(1-a*a) FNArcSin=ATN(x) EXIT DEF END IF END DEF SUB Plot(X,Y,Z,COL) SHARED xo,yo,p1,p2 LOCAL XP,YP XP=p2*X/(Z+p1)+xo YP=p2*Y/(Z+p1)+yo PSET(XP,YP),COL END SUB DEF FNPixel(X,Y,Z) SHARED xo,yo,p1,p2 LOCAL XP,YP XP=p2*X/(Z+p1)+xo YP=p2*Y/(Z+p1)+yo FNPixel=POINT(XP,YP) END DEF SUB Rot(A,B,C,X,Y,Z) LOCAL Cs,Sn,U,V SHARED i,j,k,pi 'X Rotation Cs=COS(A) Sn=SIN(A) U=Y*Cs-Z*Sn V=Y*Sn+Z*Cs i=X:j=U:k=V 'Y Rotation Cs=COS(B) Sn=SIN(B) U=i*Cs-k*Sn V=i*Sn+k*Cs i=U:j=j:k=V 'Z Rotation Cs=COS(C) Sn=SIN(C) U=i*Cs-j*Sn V=i*Sn+j*Cs i=U:j=V:k=k END SUB SUB Quad(C,X,Y,X1,Y1,X2,Y2,X3,Y3) SHARED xo,yo LOCAL XC,YC line (X +xo,Y +yo)-(X1+xo,Y1+yo),C line (X +xo,Y +yo)-(X2+xo,Y2+yo),C line (X2+xo,Y2+yo)-(X3+xo,Y3+yo),C line (X1+xo,Y1+yo)-(X3+xo,Y3+yo),C IF (X+xo)<320 THEN XC=(X3+X)/2 YC=(Y3+Y)/2 WHILE (XC+xo)<0 IF ABS(XC-X)<1E-4 THEN EXIT LOOP XC=(XC+X)/2 YC=(YC+Y)/2 WEND ELSE XC=(X1+X2)/2 YC=(Y1+Y2)/2 WHILE (XC+xo)>639 IF ABS(CX-X2)<1E-4 THEN EXIT LOOP XC=(XC+X2)/2 YC=(YC+Y2)/2 WEND END IF PAINT(XC+xo,YC+yo),C END SUB SUB Die BEEP WHILE INKEY$="" WEND PALETTE END SUB SUB CRASH(s$,a) LOCATE 1,1 PRINT s$;" ";a CALL die END SUB SUB SETCOLOURS LOCAL C RESTORE Colours FOR L=0 TO 15 READ C PALETTE L,C NEXT L END SUB Colours: REM Black,White DATA 0,63 REM Dark Grey to Light Grey DATA 24,56, 7,31 REM **** Red to Light Red DATA 4,44,60,53,39 REM **** Blue to Light Blue DATA 8, 1,57,41,11 END