/* * gfx_text_256.c — bitmap-font text rendering for mode 0x81 * (320×256×256, one byte per pixel). * * Per glyph row (8 pixels): emit 8 bytes — FG where the source bit is * 1, BG where 0. Port_Y is set once per row; the row writer wraps its * own DI / W3 save+restore so callers don't need to. */ #include #include extern uint16_t _gfx_addr_base; extern const uint8_t *_gfx_font_ptr; extern void _gfx_font_ensure(void); /* ---- Scratch shared with the asm row writer ---------------------- */ static uint8_t txt_y; static uint8_t txt_row; /* current glyph-row bit pattern */ static uint8_t txt_fg; static uint8_t txt_bg; static uint16_t txt_addr; /* VRAM address for this row */ /* Render one 8-pixel row. Self-contained DI / W3 save+restore so a * gfx_text() can be called from any context without extra ceremony. */ static void render_row_256(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_fg) ld d, a ld a, (_txt_bg) ld e, a ld a, (_txt_row) ld b, #8 ; 8 pixels in this row rr256_loop: rla ; CY = MSB, A <<= 1 jr nc, rr256_bg ld (hl), d ; FG jr rr256_next rr256_bg: ld (hl), e ; BG rr256_next: inc hl djnz rr256_loop pop af out (#0xE2), a ei ret __endasm; } void gfx_putchar256(int x, int y, char c, uint8_t fg, uint8_t bg) { _gfx_font_ensure(); if ((unsigned)x >= GFX_WIDTH || (unsigned)y >= GFX_HEIGHT) return; txt_fg = fg; txt_bg = bg; uint8_t cc = (uint8_t)c; uint16_t base = (uint16_t)(_gfx_addr_base + (unsigned)x); for (int r = 0; r < 8; r++) { int yy = y + r; if ((unsigned)yy >= GFX_HEIGHT) break; txt_y = (uint8_t)yy; txt_addr = base; /* Interleaved layout: row r of char cc lives at font[r*256 + cc]. */ txt_row = _gfx_font_ptr[r * 256 + cc]; render_row_256(); } } void gfx_text256(int x, int y, const char *s, uint8_t fg, uint8_t bg) { for (; *s; s++) { if (x >= GFX_WIDTH) break; gfx_putchar256(x, y, *s, fg, bg); x += 8; } }