--- title: "Video Graph" id: 55217 type: "computer_media" slug: "video-graph" url: "http://localhost/computer_media/video-graph/" markdown_url: "http://localhost/computer_media/video-graph.md" published_at: "2024-06-20T11:50:00+00:00" modified_at: "2026-03-31T22:59:37+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2024/06/Video-Graph.png" excerpt: "A pixel-art UDG editor lets you draw on a 16×16 grid, assign regions to user-defined characters, and instantly POKE the results into memory." 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/" genre: - name: "User Defined Graphics" slug: "user-defined-graphics" taxonomy: "genre" url: "http://localhost/type/user-defined-graphics/" media_contents: - id: 55220 title: "Long Island Sinclair Timex (LIST) User Group Library Tape #7" type: "computer_media" url: "http://localhost/computer_media/long-island-sinclair-timex-list-user-group-library-tape-7/" media_type: "Program" download_url: "https://archive.org/download/timex-sinclair-software-archive/Video%20Graph%20%28198x%29%28TS2068%29%28US%29%28Program%29.zip" mediadate: "198x" images: - url: "http://localhost/wp-content/uploads/2024/06/Video-Graph.png" media_type_tags: "User Defined Graphics" --- # Video Graph Video Graph 8000 is a pixel-art editor for designing User Defined Graphics (UDGs). The editor displays a 16×16 grid workspace where the user moves a cursor using number keys and toggles individual pixels on or off, with the grid state stored in a 32×8 string array `z$`. Up to four UDGs can be assigned at once; the program encodes each 8-row segment of the grid into byte values and POKEs them directly into UDG memory using `USR`. A custom UDG character (char \u, initialized with a DATA statement loading pattern 128,128,128,128,128,128,128,255) is used as the pixel representation within the grid. The program can save itself with `SAVE "VIDEOGRAPH" LINE 8000` for auto-restart. *** ## Program Analysis ### Program Structure The program is organized into clearly commented blocks, all residing in the 8000–9998 line range, suggesting it is one module within a larger suite: 1. **Initialization (8000–8040):** Sets screen colors, initializes cursor position variables, loads a custom UDG via DATA, and prepares the 32×8 string array `z$`. 2. **Display / Grid Draw (8100–8135):** Clears screen, draws a cross-hatch grid using `PLOT`/`DRAW`, and prints the UI labels. 3. **Main Edit Loop (8140–8190):** Positions and draws the cursor, waits for a keypress (digits 0–9), and dispatches via a computed `GO TO`. 4. **Action Handlers (8520–8690):** Separate REM-labelled blocks handle pixel off, pixel on, cursor movement (left/down/up/right). 5. **UDG Definition (8700–8810):** Prompts for up to four UDG assignments, encodes grid rows to bytes, and POKEs them into UDG memory. 6. **Save / Data (8900–9998):** Two `SAVE` lines and the UDG pixel DATA. ### Key Variables | Variable | Purpose | | --- | --- | | `l` | Cursor row (screen AT row), range 4–19 | | `c` | Cursor column (screen AT column), range 1–16 | | `r`, `b` | Mapped row/column into `z$` array (accounts for left/right halves) | | `z$` | 32×8 string array storing pixel states as characters | | `v$` | 8-char string of UDG \u chars used to fill `z$` rows | | `x$` | 4-char string holding the four UDG character assignments | ### Computed GO TO Dispatch The main keypress handler at line 8180 accepts only digit keys (ASCII 48–57, i.e., ‘0’–’9′). It dispatches with: `GO TO (CODE y$-47)*20+8500` This maps key ‘0’ → 8520 (pixel off), ‘1’ → 8540 (pixel on), ‘2’ → 8560 (unused/falls through to 8590), ‘3’/’4′ → 8600 (no-op), ‘5’ → 8600 wait (cursor left), ‘6’ → 8640, ‘7’ → 8660, ‘8’ → 8680, ‘9’ → 8700 (define UDG). The gap at lines 8560–8619 means keys ‘2’–’4′ all fall into the 8600 no-op loop, effectively ignored. ### Grid Coordinate Mapping The 16×16 editing grid is split horizontally: columns 1–8 use the left half of `z$` (rows 1–16), and columns 9–16 use the right half (rows 17–32). The mapping at line 8140 is: `LET r=l-3+16*(c>8): LET b=c-8*(c>8)` This converts screen coordinates (`l` rows 4–19, `c` columns 1–16) into `z$` indices. Each UDG covers an 8-row segment of `z$`, so four UDGs tile the full 32-row array. ### UDG Pixel Encoding The UDG definition routine at lines 8780–8800 iterates over 8 rows per UDG segment and encodes each row of `z$` into a single byte using: `LET d=d+2^p*(CODE z$(y,x)=143)` Character code 143 is the block graphic █ (char \u as initialized), representing a set pixel. The power-of-two weighting with `p` counting down from 7 assembles the byte MSB-first. The byte is then POKEd via `POKE USR x$(n)+a,d`, directly writing into UDG bitmap memory for the assigned character. ### Cursor Wrapping Cursor movement uses arithmetic wrapping rather than conditionals. For example, cursor-left at line 8630: `LET c=c-1+16*(c=1)` When `c` equals 1 (leftmost column), the expression `16*(c=1)` evaluates to 16, wrapping the cursor to the right edge. The same idiom is applied symmetrically for all four directions, keeping the cursor within bounds without any `IF` branches. ### Notable Techniques - The UDG \u character is initialized with DATA `128,128,128,128,128,128,128,255`, giving it a distinctive “pipe with base” appearance useful as a pixel marker in the grid. - `OVER 1` at line 8150 XORs the cursor character `>` onto the display without destroying the underlying pixel data. - The `INPUT FLASH 1` prompt at line 8720 gives visual feedback during UDG assignment entry. - Entering ‘9’ during UDG character assignment (`IF x$(n)="9" THEN GO TO 8120`) acts as an abort/escape back to the main display. - Line 8730’s `LET v=NOT v` inside a `FOR/NEXT` loop with a conditional `NEXT n` is an unusual control flow pattern used to toggle between upper and lower half UDG label positions. ### Bugs and Anomalies - Line 8780: `FOR y=1+8*(n-1) TO 8*8*(n-1)` — the upper bound `8*8*(n-1)` evaluates to 0 when `n=1`, meaning the loop does not execute for the first UDG. The intended expression was likely `8*n` or `8*(n-1)+8`, i.e., `1+8*(n-1) TO 8*n`. - Keys ‘2’, ‘3’, and ‘4’ in the dispatch table all land in or near the 8590/8600 no-op block and loop back to wait, effectively making those keys do nothing. This appears intentional as a placeholder, but the REM comment at 8590 reads `"y$>1 AND y$<5"` suggesting they were reserved. - The two `SAVE` lines at 8900 and 9998 save under different filenames (“VIDEOGRAPH” and “VIDEO GRAP”), likely reflecting a name-length limitation workaround or a versioning artifact. ## Source Code ``` 8000 REM VIDEOGRAPH 8005 PAPER 0: INK 7: BORDER 0 8010 LET l=4: LET c=1: LET x$=" " 8020 FOR n=0 TO 7: READ a: POKE USR "U"+n,a: NEXT n 8030 LET v$="\u\u\u\u\u\u\u\u": DIM z$(32,8) 8040 FOR n=1 TO 32: LET z$(n)=v$: NEXT n 8100 CLS : REM display 8110 FOR n=1 TO 17: PLOT 8-8*(n=9),n*8+8: DRAW 128+16*(n=9),0: PLOT n*8,8+8-8*(n=9): DRAW 0,128+16*(n=9): NEXT n 8115 PRINT AT 0,0;" VIDEOGRAPH " 8120 PRINT AT 2,1;"UDG-1";TAB 10;"UDG-3 ";AT 21,1;"UDG-2";TAB 10;"UDG-4 " 8130 FOR n=7 TO 16: PRINT AT n,22;CHR$ (n+58);"=";CHR$ (n+137);TAB 28;CHR$ (n+68);"=";CHR$ (n+147): NEXT n: PRINT AT 17,28;"U";"=";"U" 8135 REM Cursor & Controls 8140 LET r=l-3+16*(c>8): LET b=c-8*(c>8) 8150 PRINT AT l,c; OVER 1;">" 8160 PAUSE 0 8180 LET y$=INKEY$: IF CODE y$<48 OR CODE y$>57 THEN GO TO 8160 8190 GO TO (CODE y$-47)*20+8500 8520 REM Pixel off 8530 LET z$(r,b)="U": PRINT AT l,c;"U": GO TO 8140 8540 REM Pixel on 8550 LET z$(r,b)=" ": PRINT AT l,c;" ": GO TO 8140 8590 REM y$>1 AND y$<5 8600 GO TO 8160 8620 REM Cursor left 8630 PRINT AT l,c;z$(r,b): LET c=c-1+16*(c=1): GO TO 8140 8640 REM Cursor down 8650 PRINT AT l,c;z$(r,b): LET l=l+1-16*(l=19): GO TO 8140 8660 REM Cursor up 8670 PRINT AT l,c;z$(r,b): LET l=l-1+16*(l=4): GO TO 8140 8680 REM Cursor right 8690 PRINT AT l,c;z$(r,b): LET c=c+1-16*(c=16): GO TO 8140 8700 REM define user graghic 8710 LET v=0: FOR n=1 TO 4 8720 INPUT FLASH 1;"UDG-";CHR$ (n+48); FLASH 0;"=(character A to U)";x$(n): IF x$(n)="9" THEN GO TO 8120 8730 IF x$(n)=" " THEN LET v=NOT v: NEXT n: GO TO 8760 8740 LET k=(CODE x$(n)-32*(CODE x$(n)>96)): IF k<65 OR k>85 THEN LET v=NOT v: GO TO 8720 8750 PRINT AT 2+19*v,6+9*(n>2);"=";CHR$ k: LET v=NOT v: NEXT n 8760 PRINT AT 0,0; FLASH 1;"STAND-BY"; FLASH 0;" GRAPHICS BEING DEFINED" 8770 FOR n=1 TO 4: LET a=0: IF x$(n)=" " THEN NEXT n: GO TO 8810 8780 FOR y=1+8*(n-1) TO 8*8*(n-1): LET d=0: LET p=7: FOR x=1 TO 8 8790 LET d=d+2^(p)*(CODE z$(y,x)=143): LET p=p-1: NEXT x 8800 POKE USR x$(n)+a,d: LET a=a+1: NEXT y: NEXT n 8810 BEEP .1,0: BEEP .1,10: BEEP .05,18: GO TO 8115 8900 SAVE "VIDEOGRAPH" LINE 8e3 8950 REM "spaces for z$ 8960 DATA 128,128,128,128,128,128,128,255 9997 STOP 9998 SAVE "VIDEO GRAP" LINE 1 ```