Droppages

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

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

Capital Area Timex Sinclair User Group’s Library Tape.

Related Products

Related Articles

Related Content

Image Gallery

Droppages

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