--- title: "PixelPrint" id: 55866 type: "computer_media" slug: "pixelprint" url: "http://localhost/computer_media/pixelprint/" markdown_url: "http://localhost/computer_media/pixelprint.md" published_at: "2024-07-06T17:27:01+00:00" modified_at: "2026-03-30T21:44:43+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2024/07/SCR-20240705-mkdi.png" excerpt: "A machine code routine lets you place text strings at any pixel position on screen, with independent x and y displacement between characters for diagonal or scrolling effects." 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: "Cameron Hayne" slug: "cameron-hayne" taxonomy: "indiv" url: "http://localhost/indiv/cameron-hayne/" genre: - name: "Demo" slug: "demo" taxonomy: "genre" url: "http://localhost/type/demo/" - name: "Programming" slug: "programming" taxonomy: "genre" url: "http://localhost/type/programming/" media_contents: - id: 55879 title: "ISTUG Public Domain Library 7" type: "computer_media" url: "http://localhost/computer_media/istug-public-domain-library-7/" media_type: "Program" programmers: - name: "Cameron Hayne" slug: "cameron-hayne" taxonomy: "indiv" url: "http://localhost/indiv/cameron-hayne/" download_url: "https://archive.org/download/timex-sinclair-software-archive/PixelPrint%20%281984%29%28Hayne%2C%20Cameron%29%28TS2068%29%28US%29%28Program%29.zip" mediadate: "1984" images: - url: "http://localhost/wp-content/uploads/2024/07/SCR-20240705-mkdi.png" media_type_tags: "Demo, Programming" --- # PixelPrint This program demonstrates “pixelprint,” a machine code routine that renders text strings at arbitrary pixel coordinates on the screen rather than being constrained to the fixed character grid. The BASIC loader at line 9001 loads the machine code block into memory starting at address 40960 (decimal) and sets up a GOSUB-callable interface at line 9000, which passes parameters via POKEs to consecutive bytes at that address. Characters are rendered using two UDG slots (“T” and “U”) as intermediate buffers, splitting each 8×8 character into four quadrants before printing with OVER 1 to allow precise sub-character positioning. Variables p and q specify the pixel-coordinate top-left corner of the first character, while xdisp and ydisp control inter-character displacement, enabling effects like diagonal or scrolling text as demonstrated in line 9005. The program saves itself in two parts: the BASIC demonstration as “PixelPrnt” with an auto-run line, and the 395-byte machine code block as “PixelprntC” at address 40960. *** ## Program Analysis ### Program Structure The listing is a self-contained demonstration and save utility for a machine code character renderer. It splits into four logical sections: 1. **Lines 9000:** The BASIC wrapper (GOSUB target) that POKEs parameters into the machine code’s variable area and calls `RANDOMIZE USR 40976` in a loop over each character of `s$`. 2. **Lines 9001–9003:** Loader and introductory screen — loads the CODE block, sets up paper/ink, and displays usage documentation. 3. **Lines 9004–9005:** Demonstration routines showing pixel-positioned strings, including a two-pass “I am not a crook!” example and an animated scrolling “BEWARE THE IDES OF MARCH” sequence. 4. **Lines 9006–9998:** Comments, technical documentation, and the SAVE/CLEAR commands to package the program for distribution. ### Machine Code Interface The machine code block resides at address 40960 (0xA000). The first 16 bytes act as a parameter block, with each byte mapped to a named variable: | Address (hex) | BASIC variable | Purpose | | --- | --- | --- | | A000 | `p` | X pixel coordinate of first character | | A001 | `q` | Y pixel coordinate of first character | | A002 | `xdisp` | Horizontal displacement between characters | | A003 | `ydisp` | Vertical displacement between characters | | A004 | `s$(i)` | Character code for current glyph | | A005 | *row* | Internal: computed row | | A006 | *col* | Internal: computed column | | A007 | *p’* | Internal: working x | | A008 | *q’* | Internal: working y | | A009 | *dp* | Internal: x pixel offset within cell | | A00A | *dq* | Internal: y pixel offset within cell | | A00B | *8-dp* | Internal: complement of dp | | A00C | *8-dq* | Internal: complement of dq | | A00D | *address of graphic* | Pointer into ROM font data | The actual entry point called by BASIC is at address 40976 (0xA010), 16 bytes past the start of the block, leaving the first 16 bytes as the parameter/variable scratchpad. The total machine code block is 395 bytes (`SAVE "PixelprntC" CODE 40960,395`). ### Rendering Technique The routine uses UDG characters “T” and “U” as a two-cell working buffer. Each 8×8 source glyph is split into four quadrants based on the sub-character pixel offsets `dp` and `dq`. The quadrant data is composed into UDGs “T” and “U,” which are then PRINTed with `OVER 1` at the appropriate character-grid position. Because `OVER 1` XORs pixels, any previously rendered content must be erased by a second pass (explaining the repeated `GO SUB pix` calls in line 9005 before moving to the next string). ### Key BASIC Idioms - **Symbolic GOSUB target via variable:**`LET pix=9000` followed by `GO SUB pix` makes the subroutine address easily relocatable without editing every call site. - **Per-character loop at GOSUB level:** Line 9000 iterates `FOR i=1 TO LEN s$`, POKEing `CODE s$(i)` and invoking the machine code for each character individually, keeping the machine code routine simple (single-character input). - **PAUSE 0 before INKEY$ pattern:** Line 9003 uses `PAUSE 0` as an efficient keypress wait before clearing the lower screen prompt. - **Double-GOSUB erase pattern:** In line 9005, each string is rendered twice (once to draw, once to erase with OVER 1 XOR) before the next string is placed, producing a simple animation effect. ### Demonstration Sequences Line 9004 demonstrates sub-character offset rendering: “I am not a crook!” is printed at pixel (75,67), then again at (65,63) with `ydisp=-2`, creating a slight diagonal repetition. Line 9005 animates “BEWARE THE IDES OF MARCH” by scrolling upward (`ydisp=-8`, `xdisp=0`), printing each word and erasing it before moving to the next, all starting from pixel column 0. ### Save Structure Line 9998 uses `CLEAR` before saving, which resets the RAMTOP and clears variables. Two files are saved: - `"PixelPrnt"` — the BASIC program with `LINE 9001` auto-run. - `"PixelprntC"` — raw CODE at address 40960, length 395 bytes. Line 9001 loads `"PixelprntC"` from tape before the demonstration begins, making the pair a self-bootstrapping distribution package. ### Copyright Notice A `\*` (©) symbol and “1984 Cameron Hayne” appear in the `REM` at the end of line 9000, embedding a machine-readable copyright notice directly in the source. ## Source Code ``` 9000 POKE 40960,p: POKE 40961,q: POKE 40962,xdisp: POKE 40963,ydisp: FOR i=1 TO LEN s$: POKE 40964,CODE s$(i): RANDOMIZE USR 40976: NEXT i: RETURN : REM \* 1984 Cameron Hayne 9001 CLS : PRINT AT 10,1;"Leave recorder running"," data now loading": LOAD "PixelprntC"CODE : BEEP .7,4: PAPER 7: INK 0: CLS : LET pix=9000 9002 PRINT AT 0,0;"pixelprint enables you to print a string "; INK 2;"s$"; INK 0;" starting at pixel position "; INK 2;"(p,q)"; INK 0;". Here p is the x coordinate of the top left corner of the imaginary 8 x 8 square which will enclose the first character of s$. Similarlyq is the y coordinate."' INK 2;"xdisp "; INK 0;"is the displacement "'"between characters in the x "'"direction (normally 8)."'"Similarly "; INK 2;"ydisp"; INK 0;" (normally 0)"'" Example of use:" 9003 PRINT #1;AT 0,0;"PRESS ANY KEY": PAUSE 0: PRINT #1;AT 0,0;" " 9004 LET s$="I am not a crook!": LET p=75: LET q=67: LET xdisp=8: LET ydisp=0: GO SUB pix: LET p=65: LET q=63: LET ydisp=-2: GO SUB pix 9005 PAUSE 40: LET xdisp=0: LET ydisp=-8: LET s$="BEWARE": LET p=0: LET q=60: GO SUB pix: PAUSE 5: GO SUB pix: LET s$="THE": GO SUB pix: PAUSE 5: GO SUB pix: LET s$="IDES": GO SUB pix: PAUSE 5: GO SUB pix: LET s$="OF": GO SUB pix: PAUSE 5: GO SUB pix: LET s$="MARCH": GO SUB pix: PAUSE 5: GO SUB pix 9006 STOP : REM Technical info:pixelprint uses user defined graphics "T" and "U". The character is divided up into 4 parts- the top two are put into "T","U"then printed, then the bottom two. The printing is done with OVER 1 ,so anything already on the screen must first be erased 9007 REM m/c variables: A000,p A001,q A002,xdisp A003,ydisp A004,s$(i) A005,row A006,col A007,p' A008,q' A009,dp A00A,dq A00B,8-dp A00C,8-dq A00D,address of graphic 9998 CLEAR : SAVE "PixelPrnt" LINE 9001: BEEP .4,15: SAVE "PixelprntC"CODE 40960,395 ```