A life bar is a filled box. A selection frame is an outline. A tiny drawing tool needs to set, clear and inspect individual dots. These are useful pieces in their own right, and a base for more elaborate drawing.
Pick the actual display
| Machine | Code and display | Addressing choice |
|---|---|---|
| Spectrum 48K | Z80, 256×192 mono bitmap | Reuse pixel_addr; attributes are separate |
| BBC Micro MODE 4 | 6502, 320×256 mono bitmap | 512-byte row table; horizontal bytes are eight addresses apart |
| Dragon 32 PMODE 4 | 6809, 256×192 mono bitmap | Calculate y×32; consecutive linear scanlines |
| CPC 464 MODE 1 | Z80, 320×200 four-pen bitmap | Four pixels per byte, two separated bits per pen |
| Oric Atmos HIRES | 6502, 228×200 logical surface | Six pixels per byte; two reserved serial-attribute columns and canonical-byte preflight |
| Atari 800XL | 6502, ANTIC F 320×192 | CPU row tables agree with explicit LMS addresses across the 4 KiB split |
| Atari 5200 | 6502, ANTIC F 320×192 | Separate cartridge/reset-stub execution; console RAM and GTIA addresses |
| Atom, full RAM | 6502, 256×192 mono | Linear 32-byte rows; separately executed full-RAM model |
| Electron MODE 4 | 6502, 320×256 mono | Fixed ULA screen start and interleaved row tables |
| C64 standard HIRES | 6502, 320×200 stored bits | VIC bank, bitmap cells, screen-RAM colours and preserved 192-byte tail |
| Amiga A500 single plane | 68000, 320×256 stored bits | Chip RAM, byte masks and caller-owned Copper/DMA |
Each entry has the real include, a complete caller and machine-specific resource rules. The names agree where the operations agree; the memory layouts and native word order stay visible. The CPC entry supplies a packed-colour backend with explicit replace/clear/XOR pen semantics.
The Oric contract reserves serial-attribute columns and checks canonical pixel bytes before drawing. The Atari examples make the CPU/display-list agreement explicit and qualify XL and 5200 separately. These entries add primitive backends; text and geometry still require their own adapters and evidence.
Follow eight pixels across a boundary
Start at x=5 and stop before x=13. Width is 13−5=8. Repeat from y=20 up to, but not including, y=24: height 24−20=4, area 8*4=32 pixels. The first byte needs mask $07, the last $F8. Four rows therefore need eight destination-byte writes.
That is why a span deserves its own routine. It can handle the two edges and write complete interior bytes, without asking the plotter to calculate every pixel address again. The native checks measure 32 writes for a 32×8 aligned fill and 40 when it moves one pixel sideways. Those are write counts, not a cross-machine speed ranking or frame budget.
The checked interface rejects an empty, reversed or out-of-bounds request before writing. Use it when you want a mistake to leave the destination alone. If you want off-screen shapes to be partially drawn, a clipping layer should calculate the visible interval first. Clipped lines, circles and ellipses now build on these foundations, including span-filled curves. Polygon and flood fills remain bounded follow-up work.
Maths with something to draw
At x=13, 13 div 8 = 1 selects a byte column; 13 mod 8 = 5 selects a bit inside it. With the most significant bit on the left, the mask is 128 >> 5 = 4. The byte’s other seven pixels must survive.
Place a point gives position and origin an experiment you can move. These routines make it concrete in display memory. They count Y down from the top left; the experiment counts world Y upwards. Keep world and screen coordinates distinct, then convert deliberately. Each machine entry works through a real address locally; no maths course is a prerequisite.
If your scene is built from repeated pictures, native map regions may be a better starting point. Writable characters use another strategy again: cells share pictures instead of owning bitmap dots.
BASIC and the ROM graphics API
The same bounded pixel, fill and outline contract is available through BBC BASIC, Electron BASIC, CPC BASIC and Sinclair BASIC. They use physical-pixel inputs, converting once to each ROM’s graphics units. Their readable per-pixel loops have a different cost from the native byte-oriented implementations. Keep the chosen mode, origin and graphics window in the contract.