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

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