SHUTTLE.BAS
is an early software renderer written in the 1980s
for Microsoft GW-BASIC. The source code was shared on Bulletin Board Systems
and also distributed on shareware collections of that time, such as PC-SIG
Library (disk
#445).
The program renders the 3-D model of a space shuttle in the orientation given by
the user to screen, simply by drawing lines between perpectively projected
vertices.
SHUTTLE.BAS
for GW-BASIC,
running in EGA Mode 9 (Enhanced Color Display)QB Cult Magazine
(issue #2, 2000)
describes SHUTTLE.BAS
as:
One of the better 3D graphics programs ever uploaded to a GWBASIC BBS […]. This anciant program was one of the only 3D engines that anybody really took much notice of. With this release, GWBASIC programmers started to realise the potential for creating 3D graphics programs in their language.
The program reads rotation angles from user input, orientates the predefined
vertices accordingly in 3-D, applies a perspective projection, and finally
connects the vertices with edges using the LINE
intrinsic of
GW-BASIC. The graphics mode can be changed line 160 to high-resolution EGA
(fig. 1).
On modern operating systems, we can run DOSBox to execute the program, either with GW-BASIC or QuickBASIC:
C:\>GWBASIC SHUTTLE.BAS
The source code is simple enough for a quick port to FORTRAN 77, using the EGGX/ProCALL library. Instead of reading the orientation from user input, the remake just rotates the model in two angles, and renders the animation at 50 Hz. Keyboard controls could be added alternatively.
The FORTRAN 77 remake calls three procedures that are not part of the ANSI language standard:
RESULT = TIME()
INTEGER
). Required for the
initialisation of the pseudo-random number generator.RESULT = RAND(I)
REAL
).CALL SRAND(ISEED)
INTEGER
).Most modern compilers provide these procedures through extensions.
The FORTRAN 77 version is very similar to the original GW-BASIC
implementation. All vertices and edges of the space shuttle are stored in
VERTS
and EDGES
. The program first scales the
vertices in X, Y, Z, and then opens a new X11 window, sets the keyboard input
to non-blocking, selects the first canvas layer for double buffering, and
changes the pen colour to yellow. The rotation angles are initialised with
random values. They are named after their side opposites: perpendicular
P
, base B
, and hypotenuse H
.
The vertices are rotated in 3D, transformed using perspective projection, and then translated in screen coordinates. The edges are drawn as lines on layer 1 to create a wireframe look. At the end of each frame, the layer is copied to screen (fig. 2). The program stops once the user hits the escape key.
Some parameters of the renderer may be changed to custom values:
ICOL
,IDELAY
in msec,IESC
to stop the program,IW
and height IH
,ALPHA
(0 … 2π),D
,F
.Copy and save the program as shuttle.f
locally.
C ******************************************************************
C
C 3-D SPACE SHUTTLE
C
C PORT OF THE GW-BASIC PROGRAM "SHUTTLE.BAS" THAT DISPLAYS THE
C WIREFRAME MODEL OF A SPACE SHUTTLE. WRITTEN BY PHILIPP ENGEL
C (2021). REQUIRES EGGX/PROCALL LIBRARY.
C
C ******************************************************************
PROGRAM SHUTTLE
INTEGER ICOL, IDELAY, IESC, IW, IH, NEDGES, NVERTS
REAL ALPHA, D, F, PI
PARAMETER (ICOL=7, IDELAY=20, IESC=27, IW=640, IH=350)
PARAMETER (NEDGES=259, NVERTS=124)
PARAMETER (ALPHA=0.01, D=120.0, F=0.2, PI=ACOS(-1.0))
EXTERNAL COPYLAYER, GCLOSEALL, GCLR, GGETCH, GOPEN, GSETBGCOLOR
EXTERNAL GSETNONBLOCK, LAYER, LINETO, MOVETO, MSLEEP, NEWPENCOLOR
EXTERNAL WINNAME
INTEGER I, IKEY, IWIN
REAL B, H, P
REAL CH, SH, CP, SP, CB, SB
REAL AM, BM, CM, DM, EM, FM, GM, HM, IM
REAL XV, YV, ZV
REAL X, Y, Z
REAL X3, Y3, Z3
REAL U1, V1, U2, V2
INTEGER EDGES(NEDGES)
REAL VERTS(NVERTS, 3)
C
C SCALE THE VERTICES.
C
DO 10 I = 1, NVERTS
VERTS(I, 1) = VERTS(I, 1) * F
VERTS(I, 2) = VERTS(I, 2) * F
VERTS(I, 3) = VERTS(I, 3) * F
10 CONTINUE
C
C OPEN X11 WINDOW.
C
CALL GOPEN(IW, IH, IWIN)
CALL WINNAME(IWIN, 'FORTRAN SHUTTLE' // CHAR(0))
CALL GSETNONBLOCK(1)
CALL GSETBGCOLOR(IWIN, 'BLACK' // CHAR(0))
CALL LAYER(IWIN, 0, 1)
CALL GCLR(IWIN)
CALL NEWPENCOLOR(IWIN, ICOL)
C
C SET RANDOM ORIENTATION.
C
CALL SRAND(TIME())
B = RAND(0) * 2 * PI
H = RAND(0) * 2 * PI
P = RAND(0) * 2 * PI
U2 = 0.0
V2 = 0.0
C
C RENDER LOOP.
C
20 CONTINUE
CALL GCLR(IWIN)
C
C ROTATE VERTICES.
C
P = MOD(P + ALPHA, 2 * PI)
B = MOD(B + ALPHA, 2 * PI)
CH = COS(H)
SH = SIN(H)
CP = COS(P)
SP = SIN(P)
CB = COS(B)
SB = SIN(B)
AM = CB * CH - SH * SP * SB
BM = -CB * SH - SP * CH * SB
CM = CP * SB
DM = SH * CP
EM = CP * CH
FM = SP
GM = -CH * SB - SH * SP * CB
HM = SH * SB - SP * CH * CB
IM = CP * CB
XV = -D * CP * SH
YV = -D * CP * CH
ZV = -D * SP
C
C DRAW EDGES.
C
DO 30 I = 1, NEDGES
X = VERTS(ABS(EDGES(I)), 1)
Y = VERTS(ABS(EDGES(I)), 2)
Z = VERTS(ABS(EDGES(I)), 3)
X = X - XV
Y = Y - YV
Z = Z - ZV
X3 = AM * X + BM * Y + CM * Z
Y3 = DM * X + EM * Y + FM * Z
Z3 = GM * X + HM * Y + IM * Z
U1 = 135 + 13.5 * D * X3 / Y3
V1 = 80 - 11.5 * D * Z3 / Y3
IF (EDGES(I) .GT. 0) THEN
CALL MOVETO(IWIN, U2 * 2 + 75, V2 + 100)
CALL LINETO(IWIN, U1 * 2 + 75, V1 + 100)
END IF
U2 = U1
V2 = V1
30 CONTINUE
C
C COPY LAYER TO SCREEN AND CHECK FOR KEYBOARD INPUT.
C
CALL COPYLAYER(IWIN, 1, 0)
CALL MSLEEP(IDELAY)
CALL GGETCH(IKEY)
IF (IKEY .NE. IESC) GOTO 20
CALL GCLOSEALL()
DATA VERTS /0.,1.5,2.2,1.7,0.,-1.7,-2.2,-1.5,0.,2.8,4.,3.,0.,-3.,
& -4.,-2.8,0.,4.6,5.8,4.,0.,-4.,-5.8,-4.6,0.,4.5,5.8,4.,0.,-4.,
& -5.8,-4.5,0.,3.5,7.8,8.,0.,-8.,-7.8,-3.5,0.,3.8,8.,8.,0.,-8.,
& -8.,-3.8,0.,4.7,8.,8.,0.,-8.,-8.,-4.7,0.,4.7,8.,8.,0.,-8.,-8.,
& -4.7,0.,4.7,8.,8.,0.,-8.,-8.,-4.7,0.,4.7,8.,8.,0.,-8.,-8.,-4.7,
& 0.,4.7,8.,8.,0.,-8.,-8.,-4.7,0.,2.,8.8,9.,0.,-9.,-8.8,-2.,0.,2.,
& 9.2,10.,0.,-10.,-9.2,-2.,8.7,15.,35.,35.,-8.7,-15.,-35.,-35.,0.,
& 0.,0.,0.,6.,6.,11.,11.,-6.,-6.,-11.,-11.,-2.2,-2.6,-4.6,-6.5,
& -6.7,-6.5,-4.6,-2.6,-0.8,-1.5,-4.5,-7.2,-8.,-7.2,-4.5,-1.5,1.7,
& 0.,-4.4,-8.2,-9.,-8.2,-4.4,0.,4.,1.,-4.6,-9.,-9.5,-9.,-4.6,1.,
& 8.,7.,2.,-7.,-9.8,-7.,2.,7.,8.,7.5,3.,-8.,-9.8,-8.,3.,7.5,8.,7.,
& 4.,-8.7,-10.,-8.7,4.,7.,8.,7.,4.,-8.7,-10.,-8.7,4.,7.,8.,7.,4.,
& -8.7,-10.,-8.7,4.,7.,8.,7.,4.,-8.7,-10.,-8.7,4.,7.,8.,7.,4.,
& -8.7,-10.,-8.7,4.,7.,9.,8.5,1.5,-10.,-10.8,-10.,1.5,8.5,9.5,9.3,
& 1.5,-10.,-10.2,-10.,1.5,9.3,-8.7,-8.7,-10.,-10.,-8.7,-8.7,-10.,
& -10.,13.,33.,33.,14.,11.,11.,5.,5.,11.,11.,5.,5.,46.,46.,46.,
& 46.,46.,46.,46.,46.,43.,43.,43.,43.,43.,43.,43.,43.,38.,38.,38.,
& 38.,38.,38.,38.,38.,32.5,32.5,32.5,32.5,32.5,32.5,32.5,32.5,
& 26.3,26.3,26.3,26.3,26.3,26.3,26.3,26.3,21.5,21.5,21.5,21.5,
& 21.5,21.5,21.5,21.5,14.,14.,14.,14.,14.,14.,14.,14.,4.,4.,4.,4.,
& 4.,4.,4.,4.,-12.,-12.,-12.,-12.,-12.,-12.,-12.,-12.,-27.3,-27.3,
& -27.3,-27.3,-27.3,-27.3,-27.3,-27.3,-35.6,-35.6,-35.6,-35.6,
& -35.6,-35.6,-35.6,-35.6,-43.,-43.,-43.,-43.,-43.,-43.,-43.,-43.,
& -48.,-48.,-48.,-48.,-48.,-48.,-48.,-48.,21.,-16.,-36.,-40.,21.,
& -16.,-36.,-40.,-37.,-60.,-69.,-60.,-43.,-48.,-43.,-48.,-43.,
& -48.,-43.,-48./
DATA EDGES /-1,2,3,4,5,6,7,8,1,-9,10,11,12,13,14,15,16,9,-17,18,
& 19,20,21,22,23,24,17,-25,26,27,28,29,30,31,32,25,-33,34,35,36,
& 37,38,39,40,33,-41,42,43,44,45,46,47,48,41,-49,50,51,52,53,54,
& 55,56,49,-57,58,59,60,61,62,63,64,57,-65,66,67,68,69,70,71,72,
& 65,-73,74,75,76,77,78,79,80,73,-81,82,83,84,85,86,87,88,81,-89,
& 90,91,92,93,94,95,96,89,-97,98,99,100,101,102,103,104,97,-1,9,
& 17,25,33,41,49,57,65,73,81,89,97,-2,10,18,26,34,42,50,58,66,74,
& 82,90,98,-3,11,19,27,35,43,51,59,67,75,83,91,99,-4,12,20,28,36,
& 44,52,60,68,76,84,92,100,-5,13,21,29,37,45,53,61,69,77,85,93,
& 101,-6,14,22,30,38,46,54,62,70,78,86,94,102,-7,15,23,31,39,47,
& 55,63,71,79,87,95,103,-8,16,24,32,40,48,56,64,72,80,88,96,104,
& -44,105,106,107,108,92,-46,109,110,111,112,94,-81,113,114,115,
& 116,89,-82,117,118,-83,119,120,-87,121,122,-88,123,124,-117,119,
& -121,123,-118,120,-122,124/
END
The FORTRAN remake has to be linked against the static
EGGX/ProCALL library
libeggx.a
:
$ gfortran -o shuttle shuttle.f libeggx.a -lX11 -lm
$ ./shuttle