/* * gfx_text_16.c — bitmap-font text rendering for mode 0x82 * (640×256×16, 4 bits per pixel). * * Per glyph row (8 pixels): emit 4 bytes — each byte packs two * adjacent pixels as (LEFT<<4) | RIGHT. A precomputed 4-entry pair * table maps the 2-bit source pattern (LEFT*2 + RIGHT) directly to * the output byte, avoiding per-pixel mask/OR. * * Currently requires byte-aligned x (x must be even); odd x is * silently ignored. Text grids are typically aligned. */ #include #include extern uint16_t _gfx_addr_base; extern const uint8_t *_gfx_font_ptr; extern void _gfx_font_ensure(void); static uint8_t txt_y; static uint8_t txt_row; static uint16_t txt_addr; /* 4-byte lookup: index = LEFT*2 + RIGHT, value = (LEFT<<4)|RIGHT. */ static uint8_t txt_pair[4]; /* Render one 8-pixel row using the pair table — 4 byte writes. */ static void render_row_16(void) __naked { __asm di in a, (#0xE2) push af ld a, #0x50 out (#0xE2), a ld a, (_txt_y) out (#0x89), a ld hl, (_txt_addr) ld a, (_txt_row) ld c, a ; C = rotating source bits ld b, #4 ; 4 output bytes rr16_loop: ;; Extract two top bits of C as index A = LEFT*2 + RIGHT. sla c ; CY = LEFT bit; C <<= 1 ld a, #0 adc a, a ; A = LEFT sla c ; CY = RIGHT bit; C <<= 1 adc a, a ; A = LEFT*2 + RIGHT (0..3) ;; A = txt_pair[A]; preserve HL across the lookup. push hl ld e, a ld d, #0 ld hl, #_txt_pair add hl, de ld a, (hl) pop hl ld (hl), a inc hl djnz rr16_loop pop af out (#0xE2), a ei ret __endasm; } static void build_pair_table(uint8_t fg, uint8_t bg) { uint8_t f = fg & 0x0F; uint8_t b = bg & 0x0F; /* HIGH nibble = LEFT, LOW nibble = RIGHT (sprinter_graphics convention). */ txt_pair[0] = (uint8_t)((b << 4) | b); /* 00 BG BG */ txt_pair[1] = (uint8_t)((b << 4) | f); /* 01 BG FG */ txt_pair[2] = (uint8_t)((f << 4) | b); /* 10 FG BG */ txt_pair[3] = (uint8_t)((f << 4) | f); /* 11 FG FG */ } void gfx_putchar16(int x, int y, char c, uint8_t fg, uint8_t bg) { _gfx_font_ensure(); if ((unsigned)x >= GFX_WIDTH_16 || (unsigned)y >= GFX_HEIGHT_16) return; if (x & 1) return; build_pair_table(fg, bg); uint8_t cc = (uint8_t)c; uint16_t base = (uint16_t)(_gfx_addr_base + ((unsigned)x >> 1)); for (int r = 0; r < 8; r++) { int yy = y + r; if ((unsigned)yy >= GFX_HEIGHT_16) break; txt_y = (uint8_t)yy; txt_addr = base; txt_row = _gfx_font_ptr[r * 256 + cc]; render_row_16(); } } void gfx_text16(int x, int y, const char *s, uint8_t fg, uint8_t bg) { /* Build pair table once for the whole string (FG/BG don't change). */ _gfx_font_ensure(); if (x & 1) return; build_pair_table(fg, bg); for (; *s; s++) { if (x >= GFX_WIDTH_16) break; if ((unsigned)y >= GFX_HEIGHT_16) break; uint8_t cc = (uint8_t)*s; uint16_t base = (uint16_t)(_gfx_addr_base + ((unsigned)x >> 1)); for (int r = 0; r < 8; r++) { int yy = y + r; if ((unsigned)yy >= GFX_HEIGHT_16) break; txt_y = (uint8_t)yy; txt_addr = base; txt_row = _gfx_font_ptr[r * 256 + cc]; render_row_16(); } x += 8; } }