#version 330 core

out vec4 FragColor;

uniform vec2 iResolution;
uniform vec4 uTextColor;
uniform vec4 uBgColor;
uniform vec2 uTextPos;
uniform float uScale;
uniform float uSpacing;
uniform float uLineSpacing;
uniform int uTextLength;
uniform isampler1D uTextTex;
uniform isampler1D uGlyphTex;
// optional input texture provided by chain (iChannel0)
uniform sampler2D uInputTex;

// Glyph table moved to external bitmapfont.json and uploaded as integer 1D texture (uGlyphTex).

float bitAt(int bits, int x)
{
    return float((bits >> x) & 1);
}

float glyphPixel(int code, ivec2 p)
{
    if (p.x < 0 || p.x >= 5 || p.y < 0 || p.y >= 7) return 0.0;
    int glyphIndex = code;
    int rowIndex = glyphIndex * 7 + (6 - p.y);
    int rowBits = texelFetch(uGlyphTex, rowIndex, 0).r;
    int bx = 4 - p.x;
    return bitAt(rowBits, bx);
}

float charMask(vec2 frag, vec2 origin, int code, float scale)
{
    vec2 local = (frag - origin) / scale;
    ivec2 cell = ivec2(floor(local));
    return glyphPixel(code, cell);
}

float textMask(vec2 frag)
{
    float m = 0.0;
    float charW = 6.0 * uScale;
    float charH = 7.0 * uScale;
    vec2 cursor = uTextPos;

    for (int i = 0; i < 512; ++i)
    {
        if (i >= uTextLength) break;
        int code = texelFetch(uTextTex, i, 0).r;
        // line feed -> move to next line
        if (code == 10)
        {
            cursor.x = uTextPos.x;
            cursor.y -= charH * uLineSpacing;
            continue;
        }
        vec2 origin = cursor;
        m = max(m, charMask(frag, origin, code, uScale));
        cursor.x += charW * uSpacing;
    }
    return clamp(m, 0.0, 1.0);
}

void main()
{
    vec2 frag = gl_FragCoord.xy;
    float m = textMask(frag);
    // Compose over input texture if present (texture lookup returns alpha=0 for missing)
    vec4 base = texture(uInputTex, frag / iResolution);
    // If no input texture bound, texture() will sample black with alpha 0 — treat that as absent
    // If input alpha is 0 we fall back to uBgColor as base
    if (base.a == 0.0) base = uBgColor;
    // Mix base with text color using mask m (mask acts as alpha for text)
    FragColor = mix(base, uTextColor, m);
}

