This program draws a wireframe 3D cube on screen using BASIC line-drawing routines, then pokes Z80 machine code into memory to animate or manipulate the display. The X and Y coordinate arrays (each 24 elements) store the projected vertices of the cube at multiple rotation steps, with pairs of points defining edges drawn via a slope-intercept line algorithm in the subroutine at line 2500. Vertical edges are handled separately at line 3000 using a simple Y-loop PLOT. Machine code is loaded at line 4010/4060 via a hex-string POKEing routine (lines 4070–4130) that decodes two-character hex pairs using CODE arithmetic, with the entry point address decoded from the string “7530” (hex for address 30000). After the BASIC animation loop completes, execution transfers to the machine code via RAND USR 30000 at line 1040.
Program Analysis
Program Structure
The program is divided into several functional blocks:
- Initialisation (lines 20–130): Clears screen, enters FAST mode, dimensions two 24-element arrays, and zeroes several string variables.
- Coordinate data (lines 140–600): Hard-codes projected X and Y screen coordinates for 24 points — the vertices of a cube at multiple viewing angles or rotation frames, stored in
X()andY(). - Machine code loader (line 605): Calls
GOSUB 4010to poke the Z80 routine before the animation loop begins. - Main animation loop (lines 610–820): Iterates
Jfrom 1 to 21 in steps of 4, drawing each frame of the cube via subroutines at 1500, then rebuildingA$as a hex dump of screen memory before clearing and reloading the machine code hex string. - Line drawing — horizontal edges (lines 2500–2550): Slope-intercept algorithm plotting points along a line between two vertices.
- Line drawing — vertical edges (lines 3000–3030): Simple Y-loop PLOTs, plus a fixed vertical line at X=30.
- Machine code POKEing (lines 4010–4130): Decodes and writes two hex-string segments into memory.
- Address decoder (lines 5000–5010): Converts a 4-character hex string into a numeric address used as the POKE destination
Z. - Termination (lines 1010–1060): Restores SLOW mode and executes the machine code with
RAND USR 30000.
Coordinate Data and Cube Geometry
The 24 coordinate pairs in X(1)–X(24) and Y(1)–Y(24) represent 6 groups of 4 points each. The main loop steps through these in groups of 4 (J=1,5,9,13,17,21), drawing edges between consecutive pairs. This encodes a perspective or parallel projection of a rotating or multi-view cube directly as lookup tables, avoiding any trigonometric calculation at runtime.
The symmetry in the data is notable: X values for indices 9–12 match those for 17–20, and Y values are mirrored, suggesting a front-to-back rotation where intermediate frames reuse reflected coordinates.
Line Drawing Algorithm
The subroutine at line 2500 draws a line between two points using the classic slope-intercept form. Given two points (X(I), Y(I)) and (X(I+1), Y(I+1)):
M= gradient =(Y(I)-Y(I+1))/(X(I)-X(I+1))C= Y-intercept =Y(I) - M*X(I)- Points are plotted for each integer X from
X(I)toX(I+1)
This approach works for edges that are not too steep (low gradient), but will produce sparse plots for near-vertical lines. The separate vertical-edge subroutine at line 3000 compensates by iterating over Y instead of X. Note that lines 3024–3028 unconditionally draw a fixed vertical line at X=30 from Y=22 to Y=43, which appears to be the central axis spine of the cube used as a reference or construction line.
Machine Code Loading Mechanism
The hex-string POKEing idiom (lines 4070–4130) is a common technique for embedding Z80 machine code in BASIC programs. Two characters of the hex string are consumed per byte:
16*CODE A$ + CODE A$(2) - 476converts two ASCII hex digits to a byte value. SinceCODE "0"= 28 on the ZX81, the bias476 = 16*28 + 28correctly removes the character offset.Zis incremented after each POKE, advancing through memory.A$is sliced withA$(3 TO)to consume the processed pair.- The loop exits when
A$=""(line 4070).
The address decoder at line 5000 handles a 4-character hex string, computing Z = 4096*C1 + 256*C2 + 16*C3 + C4 - 122332. The bias 122332 = 4096*28 + 256*28 + 16*28 + 28 again removes the ZX81 character code offset, yielding the target address. The string "7530" decodes to hex 0x7530 = decimal 30000, confirming the machine code is loaded at address 30000.
Screen Memory Snapshot (lines 660–790)
After drawing each frame, the program reads 364 bytes of screen memory starting at the display file address obtained from system variables at addresses 16396–16397 (D_FILE). Each byte is split into high and low nibbles, converted to ZX81 character codes by adding 28, and appended to A$. This hex dump of the display is built but then discarded when A$ is overwritten at line 4060 with the machine code hex string. This suggests the screen capture code may be a remnant of a development or debugging phase, or is intended to be used differently in a more complete version.
Frame Counter and Display
Variable P counts rendered frames. At line 650, when P=6 a pound sign character is printed at position AT 10,30 — one column to the left of the standard position — suggesting a two-character display that changes at the halfway point of the 6-frame animation.
Key Variables
| Variable | Purpose |
|---|---|
X(1..24) | X screen coordinates for cube vertices |
Y(1..24) | Y screen coordinates for cube vertices |
J | Outer loop index, selects vertex group (step 4) |
I | Inner loop index, selects individual vertex pair |
M, C | Gradient and intercept for line drawing |
P | Frame counter |
Z | Current POKE destination address |
A$ | Dual-use: screen hex dump, then machine code hex string |
A | Display file base address (from D_FILE system variable) |
Notable Anomalies
- Line 4010 is referenced by
GOSUB 4010at line 605 but does not exist as a line number; the program falls through to line 4020, which is a well-known BASIC technique for entering a subroutine at an offset. - The screen memory dump into
A$(lines 660–790) is immediately overwritten at line 4060, making it effectively dead code in its current form. - Lines 5020–5050 (
STOP,SAVE,RUN) are unreachable in normal execution and serve as utility lines for saving the program. - The fixed PLOT loop at lines 3024–3028 (X=30, Y=22 to 43) runs unconditionally every time a vertical edge is drawn, potentially overdrawing and creating a persistent visual artifact.
Content
Image Gallery
Source Code
20 CLS
40 FAST
50 DIM X(24)
60 DIM Y(24)
70 LET P=0
80 LET B$=""
90 LET C$=""
100 LET D$=""
110 LET E$=""
120 LET F$=""
130 LET G$=""
140 LET X(1)=20
150 LET X(2)=40
160 LET X(3)=20
170 LET X(4)=40
180 LET X(5)=23
190 LET X(6)=37
200 LET X(7)=23
210 LET X(8)=37
220 LET X(9)=26
230 LET X(10)=34
240 LET X(11)=26
250 LET X(12)=34
260 LET X(13)=31
270 LET X(14)=30
280 LET X(15)=31
290 LET X(16)=30
300 LET X(17)=26
310 LET X(18)=34
320 LET X(19)=26
330 LET X(20)=34
340 LET X(21)=23
345 LET X(22)=37
350 LET X(23)=23
360 LET X(24)=37
370 LET Y(1)=39
380 LET Y(2)=39
390 LET Y(3)=26
400 LET Y(4)=26
410 LET Y(5)=42
420 LET Y(6)=36
430 LET Y(7)=29
440 LET Y(8)=23
450 LET Y(9)=43
460 LET Y(10)=35
470 LET Y(11)=30
480 LET Y(12)=22
490 LET Y(13)=43
500 LET Y(14)=35
510 LET Y(15)=30
520 LET Y(16)=22
530 LET Y(17)=35
540 LET Y(18)=43
550 LET Y(19)=22
560 LET Y(20)=30
570 LET Y(21)=36
580 LET Y(22)=42
590 LET Y(23)=23
600 LET Y(24)=29
605 GOSUB 4010
610 FOR J=1 TO 21 STEP 4
620 GOSUB 1500
630 PRINT AT 10,31;"£"
640 LET P=P+1
650 IF P=6 THEN PRINT AT 10,30;"£"
660 LET A=PEEK 16396+256*PEEK 16397
665 LET A$=""
670 FOR B=0 TO 363
680 LET S=PEEK (A+B)
690 LET H=INT (S/16)
700 LET L=(S/16-H)*16
710 LET L$=CHR$ (L+28)
720 LET H$=CHR$ (H+28)
730 LET A$=A$+H$+L$
790 NEXT B
800 CLS
810 GOSUB 4070
820 NEXT J
1010 CLS
1020 SLOW
1040 RAND USR 30000
1060 STOP
1500 FOR I=J TO J+3 STEP 2
1510 GOSUB 2500
1520 NEXT I
1530 FOR I=J TO J+1
1540 GOSUB 3000
1550 NEXT I
1560 RETURN
2500 LET M=(Y(I)-(Y(I+1)))/(X(I)-(X(I+1)))
2510 LET C=Y(I)-(M*X(I))
2520 FOR X=X(I) TO X(I+1)
2530 PLOT X,(M*X)+C
2540 NEXT X
2550 RETURN
3000 FOR Y=Y(I+2) TO Y(I)
3010 PLOT X(I),Y
3020 NEXT Y
3024 FOR Y=22 TO 43
3026 PLOT 30,Y
3028 NEXT Y
3030 RETURN
4020 LET A$="7530"
4030 GOSUB 5000
4060 LET A$="1EFF1D7BFE00C82A0C40015A750A7723030AFE0C20F8030AFE0C28E61602157AFE0020FA2A0C400A18E4"
4070 IF A$="" THEN RETURN
4100 POKE Z,16*CODE A$+CODE A$(2)-476
4110 LET Z=Z+1
4120 LET A$=A$(3 TO )
4130 GOTO 4070
5000 LET Z=4096*CODE A$+256*CODE A$(2)+16*CODE A$(3)+CODE A$(4)-122332
5010 RETURN
5020 STOP
5040 SAVE "1024%2"
5050 RUN
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.