--- title: "Rotating Globe" id: 71633 type: "computer_media" slug: "rotating-globe" url: "http://localhost/computer_media/rotating-globe/" markdown_url: "http://localhost/computer_media/rotating-globe.md" published_at: "2026-09-23T08:50:48+00:00" modified_at: "2026-09-23T08:51:07+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2026/09/rotating-globe.png" excerpt: "A wireframe globe rendered with 3D rotation matrices and Z80 machine code frame buffering brings smooth animated sphere graphics to life." category: - name: "Archived Media" slug: "archived-media" taxonomy: "category" url: "http://localhost/category/archived-media/" post_tag: - name: "Downloadable" slug: "downloadable" taxonomy: "post_tag" url: "http://localhost/tag/downloadable/" - name: "TS 2068" slug: "ts2068" taxonomy: "post_tag" url: "http://localhost/tag/ts2068/" model: - name: "Timex/Sinclair 2068" slug: "ts-2068" taxonomy: "model" url: "http://localhost/model/ts-2068/" indiv: - name: "Mihaly Grell" slug: "mihaly-grell" taxonomy: "indiv" url: "http://localhost/indiv/mihaly-grell/" genre: - name: "Demo" slug: "demo" taxonomy: "genre" url: "http://localhost/type/demo/" media_type: "Program" programmers: - name: "Mihaly Grell" slug: "mihaly-grell" taxonomy: "indiv" url: "http://localhost/indiv/mihaly-grell/" download_url: "https://archive.org/download/timex-sinclair-software-archive/Rotating%20Globe%20(198x)(Grell%2C%20Mihaly)(TS2068)(US)(Program).zip" mediadate: "198x" images: - url: "http://localhost/wp-content/uploads/2026/09/rotating-globe.png" media_type_tags: "Demo" --- # Rotating Globe 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`. | Phase | Subroutine | Function | Key Z80 instruction | | --- | --- | --- | --- | | Frame save (line 700) | Lines 700–720 | Copies 24×256 = 6144 bytes from display RAM to buffer at `zz` | LDIR (ED B0) | | Animation (lines 805–850) | Lines 805–850 | Installs three back-to-back LDIR blocks plus a RET, cycling four frames | LDIR 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. ## 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" ```