RLEPro

Developer(s): John Ryan
Date: 1986
Type: Program
Platform(s): TS 2068
Tags: Graphics

RLEPro decodes and displays run-length-encoded (RLE) picture data loaded as machine code from tape into memory at address 40000, then renders it using PLOT commands to build a high-resolution bitmap image. The decoder scans for a two-byte header sequence (values 71 and 72) that marks the start of the picture data, then interprets alternating run-count and color bytes. Attribute memory (22528–23295) is filled with INK 7 (white) via a POKE loop when an end-of-data sentinel is detected. After drawing, the completed screen can be saved back to tape as a SCREEN$ file, with the program prompting for a filename if one was not already supplied.


Program Structure

The program is organized into a linear initialization phase, a main decode loop, and several subroutines. Lines 4–12 handle setup: setting display attributes, prompting for a filename, loading binary data to address 40000, and initializing coordinate variables. Lines 50–230 form the main decode loop. Lines 500–550 and 600–640 are subroutines that read the run-count and color fields respectively. Lines 700–750 perform the actual PLOT rendering. Lines 800–820 handle saving the completed screen. Line 900 is a standalone tape-save routine for the BASIC program itself.

RLE Data Format and Header Detection

The binary data blob loaded at address 40000 uses a simple synchronization header. The decoder first scans for byte value 27 (ESC) at line 60–80, then scans for byte 71 (‘G’) at lines 100–120, then byte 72 (‘H’) at lines 140–160. This three-byte sequence ESC G H marks the beginning of the encoded picture data. Line 9 ensures the first byte at 40000 is 27 if it is not already, providing a fallback entry point for the scan.

Decode Loop Logic

Starting at line 180, the loop alternates between two subroutine calls and a draw call:

  1. Line 180 calls subroutine 500, which reads a run-count byte and stores C = PEEK A - 32.
  2. Line 200 calls subroutine 600, which reads a color/attribute byte (stored in C again, overwriting the run-count).
  3. Line 211 skips the draw call if C=0, then line 220 calls subroutine 700 to PLOT C pixels.

The subtraction of 32 from each raw byte offsets the data into a printable-ASCII-friendly encoding range, so a byte of 32 decodes as 0 (end of run or transparent), and values below 32 trigger the end-of-picture routine.

Coordinate Management

The drawing origin is X=0, Y=175 (top-left in Spectrum PLOT coordinates, since Y=175 is near the top of the 176-row display). Subroutine 500 advances X by the run-count and wraps to the next scanline when X exceeds 255. Subroutine 700 increments X one pixel at a time for each plotted point, also performing scanline wrap at lines 715–716. When Y goes negative the picture is complete and execution jumps to line 800.

Attribute Coloring

When the end-of-data condition is detected (a byte less than 32 is read), a FOR loop POKEs the entire attribute file (addresses 22528 to 23295) with the value 7, setting every cell to INK 7 on PAPER 0 (white on black). This is done in subroutines 500 and 600 as well as in subroutine 700, covering all possible exit paths from the decode loop.

Screen Save Feature

After drawing completes, line 800 checks whether a filename was supplied. If so, it prompts the user to press a key twice (the double-pause idiom with PAUSE 0 followed by INPUT "") before saving with SAVE a$ SCREEN$. If no filename was given, line 810 prompts for one interactively using a lower screen INPUT AT statement before proceeding to the save.

Notable Bugs and Anomalies

  • Color byte overwritten: The variable C is used for both the run-count (subroutine 500) and the color value (subroutine 600). After subroutine 600 returns, C holds only the color byte; the original run-count from subroutine 500 is lost. Subroutine 700 then uses C as the pixel count to plot, meaning it is actually plotting color-count pixels rather than run-count pixels. Whether this is intentional or a bug depends on the RLE data format conventions used by the encoder.
  • CLEAR before LOAD: Line 5 uses CLEAR 39999 to lower RAMTOP before the machine code load at line 8, protecting the loaded data from being overwritten by BASIC’s memory management — a correct and necessary technique.

Key Variables

VariableRole
ACurrent read pointer into the data block at 40000
BRaw byte value from PEEK A
CDecoded value (B−32); used as run-count then color count
DPixel counter within subroutine 700
XCurrent horizontal pixel position
YCurrent vertical pixel position (counts down from 175)
a$Tape filename for loading and saving

Source Code

    1 REM   RLE Picture program,             © 1986...John Ryan
    2 REM 
    3 REM Modified by Carl Forst         to automatically clear         Ramtop & LOAD M/C @ 40000      as well as to SAVE SCREEN$        after picture is drawn.                                                                         (GOTO 900 to save this              program to tape)                                        
    4 BEEP .5,40: BORDER 0: PAPER 0: INK 7: CLS : PAUSE 10: BEEP .75,40: PRINT AT 10,10; FLASH 1;"STOP TAPE": PAUSE 200
    5 CLEAR 39999: PRINT AT 7,0;"Run-Length-Encoded Picture Prog.";AT 10,3;"(High-Resolution Graphics)"
    6 INPUT " INPUT Pic. File Name (if known)";"(10 Chars.Max.) or just <ENTER>: "; LINE a$
    8 LOAD a$CODE 40000
    9 IF PEEK 40000<>27 THEN POKE 40000,27
   10 LET A=40000
   11 LET X=0
   12 LET Y=175
   50 CLS 
   60 LET B=PEEK A
   70 IF B=27 THEN GO TO 90
   80 LET A=A+1: GO TO 60
   90 LET A=A+1
  100 LET B=PEEK A
  110 IF B=71 THEN GO TO 130
  120 GO TO 90
  130 LET A=A+1
  140 LET B=PEEK A
  150 IF B=72 THEN GO TO 170
  160 GO TO 140
  170 LET A=A+1
  180 GO SUB 500
  190 LET A=A+1
  200 GO SUB 600
  210 LET A=A+1
  211 IF C=0 THEN GO TO 180
  220 GO SUB 700
  230 GO TO 180
  500 LET B=PEEK A
  510 LET C=B-32
  520 IF C=0 THEN RETURN 
  530 IF C<0 THEN FOR q=22528 TO 23295: POKE q,7: NEXT q: GO TO 800
  540 LET X=X+C: IF X>255 THEN LET X=X-256: LET Y=Y-1
  550 RETURN 
  600 LET B=PEEK A
  610 LET C=B-32
  620 IF C=0 THEN RETURN 
  630 IF C<0 THEN FOR q=22528 TO 23295: POKE q,7: NEXT q: GO TO 800
  640 RETURN 
  700 LET D=0
  715 IF 255<X THEN LET Y=Y-1
  716 IF 255<X THEN LET X=X-256
  717 IF Y<0 THEN FOR q=22528 TO 23295: POKE q,7: NEXT q: GO TO 800
  718 IF X>255 THEN GO TO 730
  720 PLOT X,Y
  730 LET D=D+1
  731 LET X=X+1
  740 IF D=C THEN RETURN 
  750 GO TO 710
  800 IF a$<>"" THEN PRINT #0;AT 0,0;"Press any key (twice) to save",a$;" pic. or BREAK to Stop.": PAUSE 0: INPUT "": GO TO 820
  810 INPUT AT 0,0;"Type Name of picture for saving:";"(10 Chars. max.) "; LINE a$
  820 SAVE a$SCREEN$ : GO TO 9999
  900 SAVE "RLEPRO" LINE 4: VERIFY "": STOP 
 9999 PRINT #0;AT 0,1;a$: PAUSE 0::::::: REM 

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