Skip to content

GFX640 — 2D graphics at 640×256×16

GFX640.DLL is an accelerated 2D graphics library for Sprinter in DSS mode #82 (640×256 pixels, 16 colours). The interface deliberately mirrors GFX320: the same function numbers 0–35, the same registers, descriptors, flags, palette and fade. If a program already works with GFX320, porting it to GFX640 is straightforward — mostly the coordinate rules change. Coordinates are pixels, colours are 0..15.

The shared rules for loading DLLs and passing arguments are in the libraries overview.

In mode #82 pixels are packed two per byte: the high nibble is the left pixel, the low nibble the right one. That drives the main differences:

  • Fills, frames and horizontal lines require even X and width. Copy, move and restore require even source X, destination X and width; scroll requires even X, width and shift. Violations return GFX_ERR_ARGUMENT instead of drawing “almost right”.
  • put_pixel, get_pixel, vertical and sloped lines accept any X — the library does the read-modify-write of the right nibble itself.
  • A colour above 15 is an argument error.
  • A tile here is 32×16 pixels (the same 256 bytes as 16×16 at 256 colours); the screen is a 20×16 tile grid.

For hline and vline the length and flags are packed into a single DE register: ten bits of length plus four flag bits:

DE = (length & #03FF) | (flags << 10)

The C binding does this packing in its wrapper; in assembly the constants GFX_LENGTH_MASK and GFX_LENGTH_FLAGS_SHIFT from gfx640.inc help.

The hardware key GFX_KEY_FF operates on bytes: a #FF byte skips a whole pair of colour-15 pixels. For exact per-pixel transparency there are separate tile entries 36–41 (*_TRANSPARENT): a #F nibble in a #F? or #?F byte preserves the corresponding background pixel, while a full #FF is still handled by the hardware. Without the key the same entries draw via the ordinary accelerated path and colour 15 is opaque.

#include "gfx640.h"
gfx_u8 draw(gfx_u8 handle) {
gfx_u8 status;
gfx640_bind(handle);
status = gfx640_clear(0, GFX_TARGET_FRONT);
if (status) return status;
/* a panel line: even x and width are mandatory */
status = gfx640_hline(16, 80, 288, 15, GFX_TARGET_FRONT);
if (status) return status;
/* single pixels can go anywhere, even 639 */
return gfx640_put_pixel(639, 255, 7, GFX_TARGET_FRONT);
}

The wrapper packs the hline length and flags into the DE word itself and returns the library status: 0 — success, #10..#17GFX_ERR_* codes.

Same as GFX320: the application allocates 16-KB pages (64 tiles per page), passes the table of physical page numbers to gfx_set_page_table and addresses tiles by “page + slot”. The packer accepts indexed PNG/BMP images whose pixel indices are all in 0..15:

Окно терминала
python3 gfx640/tools/tilepack.py assets.png build/tiles \
--keyed --transparent-index 0 \
--metatile-width 2 --metatile-height 2

With --keyed, every colour-15 pixel becomes transparent — including a single half of a packed pair, which is exactly what the *_TRANSPARENT entries handle.

  • The application selects video mode #82; the library never switches it.
  • Tile operations temporarily map their source into window WIN0 with interrupts disabled — the application’s code and stack must stay out of WIN0.
  • The library is not reentrant and must not be called from an interrupt handler: the ISR only sets a frame flag, while gfx_swap_buffers and gfx_fade_step are called from the main loop.
  • After every operation the library restores the mapped pages and the interrupt state.
File Purpose
GFX640.DLL the library
gfx640.inc ABI constants and descriptor offsets for sjasmplus
bindings/sdcc/gfx640.h, gfx640.lib binding for C (SDCC)
bindings/tpascal/GFX640.INC constants and helpers for Turbo Pascal
tools/tilepack.py tile packer for PNG/BMP
GFX640.EXE visual test; applications do not need it