Droppages

Developer(s): James Jones
Date: 198x
Type: Program
Platform(s): TS 2068
Tags: Graphics

This program renders a three-dimensional surface plot of the function z = 3·e^(−0.1·(x²+y+y)) using a perspective projection, then stores successive views to memory pages and plays them back as a simple animation. The projection routine at lines 20–30 applies a full rotation matrix using precomputed sines and cosines of azimuth angle theta and elevation angle phi, projecting 3-D coordinates to a 2-D screen position centered at (cx, cy). Two 12-byte machine code routines are POKEd into RAM at addresses 32000 and 32050; these use the Z80 LDIR instruction (opcode ED B0) to block-copy the screen buffer (6912 bytes from address 16384) to and from off-screen memory pages, enabling multi-frame storage and retrieval. The program iterates theta in steps of PI/4 from PI/8 to PI, drawing four rotated views and cycling through them in a continuous loop via the recall routine.


Program Analysis

Program Structure

The program is organized into several functional blocks:

  1. Initialization (lines 1–8): Clears memory above 31999, defines base addresses for two machine code routines, and POKEs them into RAM.
  2. Projection subroutine (lines 20–30): Applies a 3-D rotation and perspective transform.
  3. Main drawing loop (lines 35–140): Iterates theta, draws the surface for each viewing angle, and saves the screen to a memory page.
  4. Page-save logic (lines 1000–1050): Patches the save machine code routine with the destination address and calls it.
  5. Playback loop (lines 2000–2060): Recalls saved screen pages in sequence with a short pause between frames, then repeats indefinitely.
  6. Save lines (9000–9050): SAVE statements for backing up the BASIC program and the machine code block.

Machine Code Routines

Two 12-byte Z80 routines are installed at s=32000 (save) and r=32050 (recall). Both use the Z80 block-move instruction LDIR (mnemonic opcodes ED B0) to copy 6912 bytes (a full Spectrum display file). The DATA statements decode as follows:

AddressBytesZ80 MnemonicsPurpose
3200017, a1, a2LD DE, <dest>Destination address (patched at runtime)
3200333, 0, 64LD HL, 16384Source = screen start
320061, 0, 27LD BC, 6912Byte count (27×256 = 6912)
32009237, 176LDIRBlock copy
32011201RETReturn to BASIC

The recall routine at 32050 mirrors this with source and destination swapped: DE is loaded with 16384 (the screen) and HL with the page address, so the off-screen data is written back to the display. Addresses are patched dynamically by poking the low and high bytes into 32001/32002 (save) and 32054/32055 (recall) before each USR call.

Perspective Projection

The subroutine at lines 20–30 implements a standard perspective camera transform. The 3-D point (x, y, z) is first rotated using precomputed values s1=SIN(t), c1=COS(t), s2=SIN(phi), c2=COS(phi), producing camera-space coordinates xe, ye, ze. The offset rho=50 shifts the scene along the camera’s z-axis. Screen coordinates are then computed as sx = d*xe/ze + cx and sy = cy + d*ye/ze with focal length d=350 and screen center (cx, cy) = (127, 87).

Surface Function and Drawing

The surface is defined at line 50 as DEF FN z(x) = 3*EXP(-.1*(x*x+y+y)). Note that the exponent argument contains y+y (i.e., 2y) rather than the expected y*y, which is almost certainly a typo — the intended function is the Gaussian bell surface z = 3·e^(−0.1·(x²+y²)). The outer loop iterates x from 10 to −10 in steps of −0.1 and the inner loop iterates integer y from −10 to 10. The variable fl acts as a “pen down” flag: when a valid screen point is found after an out-of-bounds gap, PLOT is used to begin a new stroke; otherwise DRAW connects to the previous point using the stored values sx1, sy1. However, lines 125–130 overwrite sx/sy with themselves before DRAW, meaning the DRAW always has delta arguments of zero — this is a bug; the previous screen coordinates should have been saved before recalculating sx and sy for the new point.

Memory Page Addressing

Each of the four screen pages is stored at address a = p*7000 + 26000, giving addresses 33000, 40000, 47000, and 54000 for pages 1–4. These regions lie well above the BASIC/display area but must fit within a 64 KB address space; page 4 at 54000 + 6912 = 60912 is within bounds. The low and high byte decomposition uses integer arithmetic: a2 = INT(a/256), a1 = a - a2*256, avoiding the BASIC INT/MOD combination.

Notable Techniques and Anomalies

  • Commented-out INPUT and IF statements at lines 1000–2050 suggest the program was originally interactive but was simplified to run automatically with p auto-incrementing and q driven by a FOR loop.
  • LET l=1 at line 120 appears to set a variable that is never subsequently used — likely a remnant of a color or attribute selection feature.
  • The CLEAR 31999 at line 3 sets RAMTOP just below the machine code, protecting it from BASIC’s memory manager.
  • The playback loop (lines 2000–2060) runs indefinitely via GO TO 2000 after exhausting the FOR loop, creating a continuous slideshow.
  • The REM at the end of line 2050 contains RETURN, suggesting an earlier design where the recall block was a subroutine.
  • Two separate SAVE "droppages" LINE 0 statements exist at lines 9000 and 9050, which is redundant.

Content

Appears On

Watch Gaussian bell curves rendered in perspective, animated saddle surfaces cycling through memory pages, and a rotating 3D pyramid with hidden-line removal — Tape 9 is a showcase of what the TS 2068 can do with math and machine code.

Related Products

Related Articles

Related Content

Image Gallery

Source Code

    1 REM  this poqram 6.4
    2 REM draws a surface z=f(x,y)
    3 CLEAR 31999: LET s=32000: LET r=32050
    4 RESTORE : FOR j=0 TO 11: READ a: POKE s+j,a: NEXT j
    5 FOR j=0 TO 11: READ a: POKE r+j,a: NEXT j
    6 DATA 17,232,128,33,0,64,1,0,27,237,176,201
    7 DATA 17,0,64,33,232,128,1,0,27,237,176,201
    8 LET p=0
    9 GO TO 2000
   10 GO TO 35
   20 LET xe=-x*s1+y*c1: LET ye=-x*c1*c2-y*s1*c2+z*s2: LET ze=-x*s2*c1-y*s2*s1-z*c2+rho
   30 LET sx=d*xe/ze+cx: LET sy=cy+d*ye/ze: RETURN 
   35 FOR t=PI/8 TO PI+.1 STEP PI/4
   38 REM t=theta
   40 LET rho=50: LET d=350: LET phi=1: LET cx=127: LET cy=87: LET s1=SIN (t): LET s2=SIN (phi): LET c1=COS (t): LET c2=COS (phi)
   50 DEF FN z(x)=3*EXP (-.1*(x*x+y+y))
   60 REM color
   70 FOR x=10 TO -10 STEP -.1
   80 LET fl=0
   90 FOR y=-10 TO 10
  100 LET z=FN z(x): GO SUB 20
  110 IF sx<0 OR sx>255 OR sy<0 OR sy>175 THEN LET fl=0: GO TO 140
  120 IF fl=0 THEN LET l=1: PLOT sx,sy
  125 LET sx1=sx: LET sy1=sy
  130 DRAW (sx1-sx),(sy1-sy)
  140 NEXT y: NEXT x
 1000 LET p=p+1: REM INPUT "Stor as page no. (1-4) ";p
 1010 LET p=INT p: REM IF p<1 OR p>4 THEN GO TO 1000
 1020 LET a=p*7000+26000: LET a2=INT (a/256): LET a1=a-a2*256
 1030 POKE 32001,a1: POKE 32002,a2
 1040 LET n=USR s
 1045 IF p=4 THEN GO TO 2000
 1046 CLS 
 1050 NEXT t
 2000 FOR q=1 TO 4: REM INPUT "Recall page no. (1-4) ";p
 2010 LET p=INT p: REM IF p<1 OR p>4 THEN GO TO 2000
 2020 LET a=q*7000+26000: LET a2=INT (a/256): LET a1=a-a2*256
 2030 POKE 32054,a1: POKE 32055,a2
 2040 LET n=USR r
 2045 PAUSE 22
 2050 NEXT q: REM RETURN 
 2060 GO TO 2000
 9000 SAVE "droppages" LINE 0
 9005 STOP 
 9010 SAVE "droppages"CODE 32000,30000
 9050 SAVE "droppages" LINE 0

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

Scroll to Top