1	REM 3D DISPLAY PROGRAM
	DIM VIEW(4,4),T(4,4),TA(4,4),POINT(4)
	DIM I,J,K,X,Y,Z,X1,Y1,Z1
	DIM NPOINTS/0/,MAXPOINTS/30/,XSTART[30],YSTART[30],ZSTART[30],XEND[30],YEND[30],ZEND[30]
	DIM VSX/127.5/,VCX/256/,VSY/127.5/,VCY/128/
	DIM WINDOWDIST/4/,WINDOWHEIGHT/1/,WINDOWTILT/0/
	DIM FILE$(50)
	DIM COMMAND$[10],LINE
	DIM VIEWERX/0/,VIEWERY/0/,VIEWERZ/-10/
	DIM TARGETX/0/,TARGETY/0/,TARGETZ/0/
	DIM THETA,TX,TY,TZ,TEMP,S1,S2,S3
	DIM CLEARSCREEN$/:C/,TOP$/:1B," 0 255",:1B,"-128 48",:1B," 0 255"/
	DIM MOVETO$/:1B," "/,LINETO$/:1B,"&"/
	DIM ROTATEDELTA,SAVEWINDOWTILT

	WRITE #0, CLEARSCREEN$
100	WRITE #0, TOP$\ INPUT "WHAT NEXT ? " COMMAND$
120	IF COMMAND$="STOP" THEN STOP
130	IF COMMAND$="NEW" THEN 200
140	IF COMMAND$="DELETE" THEN 300
150	IF COMMAND$="VIEW" THEN 500
160	IF COMMAND$="WINDOW" THEN 400
170	IF COMMAND$="AGAIN" THEN 510
180	IF COMMAND$="LIST" THEN 600
	IF COMMAND$="MATRIX" THEN 700
	IF COMMAND$="SAVE" THEN 800
	IF COMMAND$="LOAD" THEN 900
	IF COMMAND$="ROTATE" THEN 1000
190	GOTO 100

200	IF NPOINTS=MAXPOINTS THEN PRINT "LINE LIST IS FULL"\ GOTO 100
	LET NPOINTS=NPOINTS+1
210	INPUT "BEGIN X,Y,Z: " XSTART(NPOINTS),YSTART(NPOINTS),ZSTART(NPOINTS)
220	INPUT "END X,Y,Z: " XEND(NPOINTS),YEND(NPOINTS),ZEND(NPOINTS)
230	LET LINE=NPOINTS\GOSUB 10000\ REM DRAW LINE
240	GOSUB 10800\ REM PUT UP ENDPOINT LABELS
250	GOTO 100


300	REM DELETE A LINE FROM LINE LIST
	IF NPOINTS = 0 THEN PRINT "YOU CAN'T DO THAT"\ GOTO 100
310	INPUT "BEGIN X,Y,Z: " X,Y,Z
320	INPUT "END X,Y,Z: " X1,Y1,Z1
330	FOR LINE=1 TO NPOINTS
340	IF XSTART(LINE)=X AND YSTART(LINE)=Y AND ZSTART(LINE)=Z...
&	AND XEND(LINE)=X1 AND YEND(LINE)=Y1 AND ZEND(LINE)=Z1 THEN 380
350	NEXT LINE
360	PRINT "SORRY, I DON'T HAVE THAT LINE"
370	GOTO 100
380	GOSUB 10000\ REM DRAW THE LINE AGAIN, THEREBY ERASING IT
390	GOSUB 10800\ REM WRITE LINE COORDINATES, ERASING THEM
	LET XSTART(LINE)=XSTART(NPOINTS)
	LET YSTART(LINE)=YSTART(NPOINTS)
	LET ZSTART(LINE)=ZSTART(NPOINTS)
	LET XEND(LINE)=XEND(NPOINTS)
	LET YEND(LINE)=YEND(NPOINTS)
	LET ZEND(LINE)=ZEND(NPOINTS)
	LET NPOINTS=NPOINTS-1
	GOTO 100

400	REM SELECT NEW WINDOW DIMENSIONS
	INPUT "DISTANCE TO WINDOW: " WINDOWDIST
	INPUT "WINDOW HEIGHT/2: " WINDOWHEIGHT
	INPUT "WINDOW TILT: " WINDOWTILT
	GOTO 510

500	REM SELECT NEW VIEWING POSITION
	INPUT "SELECT YOUR X,Y,Z: " VIEWERX,VIEWERY,VIEWERZ
	INPUT "LOOKING TOWARDS... " TARGETX,TARGETY,TARGETZ
510	GOSUB 550
	GOTO 100

550	REM COMPUTE TRANSFORM AND DRAW
	GOSUB 20000\ REM COMPUTE TRANSFORMATION MATRIX
	WRITE #0, CLEARSCREEN$
	IF NPOINTS=0 THEN RETURN
	FOR LINE=1 TO NPOINTS
		GOSUB 10000\ REM DISPLAY A LINE
		GOSUB 10800\! DISPLAY THE END POINTS
	NEXT LINE
	RETURN

600	REM LIST ALL THE LINES STORED SO FAR
	WRITE #0, CLEARSCREEN$
	WRITE #0, MOVETO$
	PRINT 0;200
	IF NPOINTS=0 THEN 100
	FOR LINE=1 TO NPOINTS
		PRINT '(';XSTART[LINE];',';YSTART[LINE];
		PRINT ',';ZSTART[LINE];')';
		PRINT TAB(30);'(';XEND[LINE];',';
		PRINT YEND[LINE];',';ZEND[LINE];')';
		LET POINT(1)=XSTART[LINE]
		LET POINT(2)=YSTART[LINE]
		LET POINT(3)=ZSTART[LINE]
		LET POINT(4)=1
		GOSUB 51000\! REM MULT POINT BY VIEW MATRIX
		GOSUB 52000\! CONVERT TO PERSPECTIVE AND VIEWPORT
		PRINT TAB(60);'(';X;',';Y;')',
		LET POINT(1)=XEND[LINE]
		LET POINT(2)=YEND[LINE]
		LET POINT(3)=ZEND[LINE]
		LET POINT(4)=1
		GOSUB 51000\! MULT POINT BY VIEW MATRIX
		GOSUB 52000\! CONVERT TO PERSPECTIVE AND VIEWPORT
		PRINT '(';X;',';Y;')'
	NEXT LINE
	GOTO 100

700	REM SHOW VIEW MATRIX
	PRINT CLEARSCREEN$
	WRITE #0, MOVETO$
	PRINT 0;200
	FOR I=1 TO 4
		FOR J=1 TO 4
			PRINT VIEW(I,J),
		NEXT J
		PRINT
	NEXT I
	GOTO 100

800	REM SAVE THE LINES IN A DISK FILE
	IF NPOINTS=0 THEN PRINT "NOTHING TO SAVE!!"\GOTO 100
	INPUT "FILE: " FILE$
	CREATE #1,FILE$
	WRITE #1,WINDOWDIST,WINDOWHEIGHT,WINDOWTILT
	WRITE #1,VIEWERX,VIEWERY,VIEWERZ
	WRITE #1,TARGETX,TARGETY,TARGETZ
	FOR LINE=1 TO NPOINTS
		WRITE #1,XSTART(LINE),YSTART(LINE),ZSTART(LINE)
		WRITE #1,XEND(LINE),YEND(LINE),ZEND(LINE)
	NEXT LINE
	CLOSE #1
	GOTO 100

900	REM FETCH LINES FROM A DISK FILE
	INPUT "FILE: " FILE$
	OPEN #1,FILE$
	READ #1,WINDOWDIST,WINDOWHEIGHT,WINDOWTILT
	READ #1,VIEWERX,VIEWERY,VIEWERZ
	READ #1,TARGETX,TARGETY,TARGETZ
	NPOINTS = 1
910	READ #1,XSTART(NPOINTS),YSTART(NPOINTS),ZSTART(NPOINTS)
	IF EOF(1) THEN LET NPOINTS=NPOINTS-1\CLOSE #1\GOTO 510
	READ #1,XEND(NPOINTS),YEND(NPOINTS),ZEND(NPOINTS)
	NPOINTS=NPOINTS+1
	GOTO 910

1000	REM ROTATE THE OBJECT THRU 360 DEGREES
	INPUT "ROTATION STEP: " ROTATEDELTA
	SAVEWINDOWTILT=WINDOWTILT
	FOR WINDOWTILT=WINDOWTILT TO WINDOWTILT+2*PI STEP ROTATEDELTA
	GOSUB 550
	NEXT WINDOWTILT
	WINDOWTILT=SAVEWINDOWTILT
	GOTO 100

10000	REM DISPLAY A LINE
	LET POINT(1)=XSTART[LINE]
	LET POINT(2)=YSTART[LINE]
	LET POINT(3)=ZSTART[LINE]
	LET POINT(4)=1
	GOSUB 51000\! REM MULT POINT BY VIEW MATRIX
	GOSUB 52000\! CONVERT TO PERSPECTIVE AND VIEWPORT
	IF X<0 OR X>511 OR Y<0 OR Y>255 THEN 10010
	WRITE #0, MOVETO$
	PRINT X;Y
	LET POINT(1)=XEND[LINE]
	LET POINT(2)=YEND[LINE]
	LET POINT(3)=ZEND[LINE]
	LET POINT(4)=1
	GOSUB 51000\! MULT POINT BY VIEW MATRIX
	GOSUB 52000\! CONVERT TO PERSPECTIVE AND VIEWPORT
	IF X<0 OR X>511 OR Y<0 OR Y>255 THEN 10010
	WRITE #0, LINETO$
	PRINT X;Y
10010	RETURN

10800	REM DISPLAY COORDINATES OF ENDPOINTS OF LINE
	RETURN	\! BECUZ I'M NOT SURE THIS IS THE RIGHT THING TO DO...
10890	REM PRINT X,Y
	PRINT " (";X;',';Y;")";
	RETURN

20000	REM COMPUTE TRANSFORM OPERATION
	GOSUB 50900\! INITZ VIEW XFORM
	TX=-VIEWERX\TY=-VIEWERY\TZ=-VIEWERZ
	GOSUB 50600\! REM TRANSLATE
	IF TARGETZ<>VIEWERZ
	THEN LET THETA=ATN((TARGETX-VIEWERX)/ABS(TARGETZ-VIEWERZ))
	ELSE LET THETA=SGN(TARGETX-VIEWERX)*PI/2
	IF TARGETZ<VIEWERZ THEN LET THETA=PI-THETA
	GOSUB 50300\! ROTATE ABOUT Y AXIS TO ALIGN Z
	LET TEMP=SQR((TARGETZ-VIEWERZ)^2+(TARGETX-VIEWERX)^2)
	IF TEMP<>0
	THEN LET THETA=ATN((TARGETY-VIEWERY)/TEMP)
	ELSE LET THETA=SGN(TARGETY-VIEWERY)*PI/2
	IF TARGETZ<VIEWERZ THEN LET THETA=PI-THETA
	GOSUB 50200\! ROTATE ABOUT X AXIS TO ALIGN Z AXIS WITH DESIRED DIRECTION
	LET THETA=WINDOWTILT
	GOSUB 50400\! ROTATE ABOUT Z TO ALIGN X AND Y AXES
	GOSUB 50800\! REM CONVERT COORDINATES TO CLIPPING COORDINATE SYSTEM
	REM NOW MULTIPLYING A POINT IN ORIGINAL COORDINATE SYSTEM...
	REM BY "VIEW" MATRIX CONVERTS ITS POSITION TO THE EYE COORDINATE SYSTEM
	RETURN

50000	REM ZERO THE HOMOGENEOUS COORDINATES OF MAT T
	FOR I=1 TO 4\FOR J=1 TO 4\T(I,J)=0\NEXT J\NEXT I
	T(4,4)=1
	RETURN

50100	REM MATRIX MULTIPLY - VMAT := VMAT * TMAT
	FOR I=1 TO 4
		FOR J=1 TO 4
			TEMP=0
			FOR K=1 TO 4
				TEMP=TEMP+VIEW(I,K)*T(K,J)
			NEXT K
			TA(I,J)=TEMP
		NEXT J
	NEXT I
	FOR I=1 TO 4\FOR J=1 TO 4\VIEW(I,J)=TA(I,J)\NEXT J\NEXT I
	RETURN

50200	REM X AXIS ROTATION (ANGLE=THETA)
	GOSUB 50000
	T(1,1)=1
	TX=COS(THETA)\TY=SIN(THETA)
	T(2,2)=TX\T(3,3)=TX
	T(3,2)=TY\T(2,3)=-TY
	GOSUB 50100
	RETURN

50300	REM Y AXIS ROTATION (ANGLE=THETA)
	GOSUB 50000
	T(2,2)=1
	TX=COS(THETA)\TY=SIN(THETA)
	T(1,1)=TX\T(3,3)=TX
	T(3,1)=-TY\T(1,3)=TY
	GOSUB 50100
	RETURN

50400	REM Z AXIS ROTATION (ANGLE=THETA)
	GOSUB 50000
	T(3,3)=1
	TX=COS(THETA)\TY=SIN(THETA)
	T(1,1)=TX\T(2,2)=TX
	T(2,1)=TY\T(1,2)=-TY
	GOSUB 50100
	RETURN

50500	REM SCALING S1=X, S2=Y, S3=Z
	GOSUB 50000
	T(1,1)=S1\T(2,2)=S2\T(3,3)=S3
	GOSUB 50100
	RETURN

50600	REM TRANSLATION TX=X, TY=Y, TZ=Z
	GOSUB 50000
	FOR I=1 TO 3\T(I,I)=1\NEXT I
	T(4,1)=TX\T(4,2)=TY\T(4,3)=TZ
	GOSUB 50100
	RETURN

50700	REM CONVERT TO LEFT HAND COORDINATES
	GOSUB 50000
	T(1,1)=-1\T(2,3)=-1\T(3,2)=1
	GOSUB 50100
	RETURN

50800	REM PERSPECTIVE MATRIX
	REM USED IN CLIPPING ALGORITHM
	GOSUB 50000
	TEMP=WINDOWDIST/WINDOWHEIGHT
	T(1,1)=TEMP\T(2,2)=TEMP\T(3,3)=1
	GOSUB 50100
	RETURN

50900	REM INITZ VIEWING TRANSFORM TO IDENTITY
	FOR I=1 TO 4\FOR J=1 TO 4\LET VIEW(I,J)=0\NEXT J\VIEW(I,I)=1\NEXT I
	RETURN

51000	REM MULTIPLY POINT BY VIEW MATRIX
	X=0\Y=0\Z=0
	FOR J=1 TO 4
		X=X+POINT(J)*VIEW(J,1)
		Y=Y+POINT(J)*VIEW(J,2)
		Z=Z+POINT(J)*VIEW(J,3)
	NEXT J
	RETURN

52000	REM CONVERT TO PERSPECTIVE AND VIEWPORT
	IF Z<>0
	THEN X=INT((X/Z)*VSX+VCX) \ Y=INT((Y/Z)*VSY+VCY)
	ELSE X=0 \ Y=0
	RETURN

	END
