/*
 * 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 <gfx.h>
#include <stdint.h>

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;
    }
}
