Rotating Globe

Developer(s): Mihaly Grell
Date: 198x
Type: Program
Platform(s): TS 2068
Tags: Demo

This program renders a wireframe rotating globe using 3D rotation matrices applied to spherical coordinates. It draws latitude lines by iterating over declination angles and longitude lines by iterating over azimuth angles, using PLOT and DRAW to connect projected points on screen. The rotation is parameterized by two Euler angles, phi (forward tilt, 45°) and psi (side tilt, −30°), with precomputed matrix elements (a21, a23, a31, a33) to avoid redundant trigonometry in the inner loops. A machine code routine is POKEd into address 64000 to perform a fast block memory copy (using the Z80 LDIR instruction) that saves each of four globe frames to a buffer region starting at address 32000, enabling animation by cycling through stored frames. The elliptical outline of the globe (accounting for the 1.22 aspect-ratio correction) is drawn as a final contour using incremental DRAW steps around a 360° circle.

Program Structure

The program is divided into several functional phases:

  1. Initialization (lines 10–122): Sets rotation angles, step sizes, scale, and precomputes rotation matrix elements from the Euler angles phi and psi.
  2. Latitude line drawing (lines 125–210): Nested loops over declination d (90° to −90°) and azimuth a (0° to 360°) draw latitude parallels using PLOT/DRAW with back-face culling on x.
  3. Longitude line drawing (lines 280–400): Loops restructured to iterate azimuth a in the outer loop and declination d in the inner loop, drawing meridians.
  4. Outline ellipse (lines 405–430): Draws the limb of the globe as an ellipse using incremental DRAW steps with a 1.22 aspect-ratio divisor for the vertical axis.
  5. Frame save and animation (lines 500–920): A machine code LDIR block copy saves each rendered frame to a memory buffer. After all four frames are drawn, a second machine code sequence cycles through them in a loop, producing animation.

3D Rotation Mathematics

The globe uses a standard spherical-to-Cartesian conversion followed by a two-axis rotation. For each latitude d and longitude a, the unit-sphere coordinates are:

  • x0 = cos(d) * cos(a)
  • y0 = cos(d) * sin(a)
  • sd = sin(d)

These are then transformed by the rotation matrix. Only the projected y and z coordinates are needed for screen display; x is used solely for back-face culling (points with x < 0 are on the far side of the globe and are skipped). The matrix elements a21, a23, a31, a33 are precomputed outside the loops at lines 110–120 to minimize repeated trigonometric calls.

Screen Projection

The screen coordinates are computed as:

  • yp = 128 + y * sc (horizontal, centered at pixel 128)
  • zp = 88 + z * sc / 1.22 (vertical, centered at pixel 88, with aspect ratio correction)

The divisor 1.22 compensates for the non-square pixel aspect ratio of the display, ensuring the globe appears circular rather than elliptical on screen. The scale factor sc = 100 maps the unit sphere to approximately the full screen height.

PLOT/DRAW Line Drawing Idiom

The program uses a common pen-up/pen-down idiom controlled by the flag variable p. When p = 0, the current point is PLOTted and p is set to 1. When p = 1, a DRAW is issued relative to the previous screen position stored in y1 and z1. This avoids recalculating absolute coordinates for each segment and is efficient for connected curves. The flag is reset to 0 whenever a point fails the back-face test (x < 0), correctly breaking the polyline at the limb of the sphere.

Machine Code Usage

Two distinct machine code routines are POKEd into address 64000 and executed via RANDOMIZE USR 64000.

PhaseSubroutineFunctionKey Z80 instruction
Frame save (line 700)Lines 700–720Copies 24×256 = 6144 bytes from display RAM to buffer at zzLDIR (ED B0)
Animation (lines 805–850)Lines 805–850Installs three back-to-back LDIR blocks plus a RET, cycling four framesLDIR chain

The DATA at line 710 encodes: LD HL, 16384; LD DE, zz; LD BC, 6144 (screen size, hardcoded as 0×1800); LDIR; RET. The low and high bytes of zz are computed inline using zz - INT(zz/256)*256 and INT(zz/256), a standard technique for splitting a 16-bit address into bytes within a DATA statement.

The animation loop at lines 900–920 calls the frame-cycling machine code repeatedly while no key is pressed (INKEY$ = ""), and spins on a keypress check at line 910 before looping back.

Frame Buffer Layout

Four frames are rendered (outer loop m = 0 TO 3). Each frame’s rendered display is copied to a successive 7000-byte region (slightly larger than the 6144-byte display file) starting at 32000, 39000, 46000, and 53000. The CLEAR 31999 at lines 10 and 800 sets the RAMTOP to protect this buffer area from BASIC’s variable space.

The Four-Frame Rotation

Each of the four frames shifts the starting azimuth of both latitude and longitude line sampling by m * sta / 4 degrees (i.e., 0°, 5°, 10°, 15° for sta = 20). This produces four slightly rotated views of the same globe, giving the illusion of slow rotation when the frames are cycled by the animation machine code.

Anomalies and Notes

  • Lines 280–281 compute dr, cd, and sd from d before the inner FOR d loop at line 302 begins — these values are immediately overwritten by line 306 and are therefore dead code, having no effect on output.
  • The BC register pair in the LDIR machine code is set to 1, 0, 24 in the DATA, which decodes as LD BC, 0×1801 (6145 bytes) rather than exactly 6144. This copies one extra byte beyond the display file, which is harmless in practice.
  • Lines 950–9998 are purely documentary REM statements indicating related SAVE commands and a loader program, with no effect on execution.

Image Gallery

Source Code

    5 REM GLOBE ROTATING ROUTINE
    7 REM BY MIHALY GRELL
   10 CLEAR 31999
   20 REM Phi=Forward Rotation
   25 REM Psi=Side Rotation
   30 REM Std=Step for Latitude
   35 REM Sta=Step for Longitude
   37 REM Sc=Plot Scale Factor
   38 REM ***********************
   40 LET psi=-30:LET phi=45
   50 LET std=10:LET sta=20
   60 LET sc=100:LET dtr= PI/180
   70 LET ch= COS (phi*dtr)
   80 LET sh= SIN (phi*dtr)
   90 LET cs= COS (psi*dtr)
  100 LET ss= SIN (psi*dtr)
  110 LET a21=ss*sh:LET a23=-ss*ch
  120 LET a31=-cs*sh:LET a33=cs*ch
  122 LET zz=32000
  125 FOR m=0 TO 3
  130 FOR d=90 TO -90 STEP -std
  135 LET p=0
  140 LET dr=d*dtr:LET cd= COS dr:LET sd= SIN dr
  145 FOR a=0+m*sta/4 TO 360+m*sta/4 STEP sta
  150 LET ar=a*dtr:LET sa= SIN ar:LET ca= COS ar
  155 LET x0=cd*ca:LET y0=cd*sa
  160 LET x=ch*x0+sh*sd
  165 IF x<0 THEN LET p=0:GO TO 200
  175 LET y=a21*x0+cs*y0+a23*sd
  180 LET z=a31*x0+ss*y0+a33*sd
  182 LET yp=128+y*sc:LET zp=88+z*sc/1.22
  190 IF p THEN DRAW yp-y1,zp-z1:LET y1=yp:LET z1=zp
  195 IF p=0 THEN PLOT yp,zp:LET y1=yp:LET z1=zp:LET p=1
  200 NEXT a
  210 NEXT d
  280 LET dr=d*dtr:LET cd= COS dr:LET sd= SIN dr
  290 FOR a=0+m*sta/4 TO 360+m*sta/4 STEP sta
  300 LET ar=a*dtr:LET sa= SIN ar:LET ca= COS ar
  301 LET p=0
  302 FOR d=90 TO -90 STEP -std
  306 LET dr=d*dtr:LET cd= COS dr:LET sd= SIN dr
  310 LET x0=cd*ca:LET y0=cd*sa
  320 LET x=ch*x0+sh*sd
  330 IF x<0 THEN LET p=0:GO TO 390
  340 LET y=a21*x0+cs*y0+a23*sd
  350 LET z=a31*x0+ss*y0+a33*sd
  360 LET yp=128+y*sc:LET zp=88+z*sc/1.22
  370 IF p THEN DRAW yp-y1,zp-z1:LET y1=yp:LET z1=zp
  380 IF p=0 THEN PLOT yp,zp:LET y1=yp:LET z1=zp:LET p=1
  390 NEXT d
  400 NEXT a
  405 REM         Contours
  407 LET first=0
  410 FOR i=0 TO 360 STEP 15
  415 LET ang=i*dtr
  420 IF first=0 THEN LET q1= COS ang:LET q2= SIN ang:PLOT 128+sc*q1,88+sc/1.22*q2:LET first=1
  425 LET r1= COS ang:LET r2= SIN ang:DRAW sc*(r1-q1),sc/1.22*(r2-q2):LET q1=r1:LET q2=r2
  430 NEXT i
  500 GO SUB 700
  510 LET zz=zz+7000
  520 CLS 
  600 NEXT m
  610 GO TO 800
  700 RESTORE 710:FOR n=64000 TO 64011:READ q:POKE n,q:NEXT n:RANDOMIZE USR 64000
  710 DATA 33,0,64,17,zz- INT (zz/256)*256, INT (zz/256),1,0,24,237,176,201
  720 RETURN 
  800 CLEAR 31999
  803 LET zz=32000
  805 FOR f=0 TO 33 STEP 11
  810 RESTORE 820:FOR n=64000+f TO 64010+f:READ q:POKE n,q:NEXT n
  820 DATA 33,zz- INT (zz/256)*256, INT (zz/256),17,0,64,1,0,24,237,176
  830 LET zz=zz+7000
  840 NEXT f
  850 POKE 64044,201
  900 IF INKEY$="" THEN RANDOMIZE USR 64000
  910 IF INKEY$ <>"" THEN GO TO 910
  920 GO TO 900
  950 GO TO 1: REM SAVE "glbtrn.B1"
  960 REM SAVE "glbfrm.C1"CODE 32000,28000
 9992 REM SAVE "GLOBE.B1" LINE 1
 9998 REM PRINT USR 100:LOAD "L.B1"

Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.