/*
 * MIT License
 * Author: Mark Allyn
 *
 * phosphor.frag — maps the single-channel phosphor energy texture to
 * the P7 colour sequence (blue → green → yellow-green → dark) and
 * applies a simple inline bloom (box-filter glow) to bright pixels.
 *
 * Coordinate system: gl_FragCoord.xy in GL viewport pixels (origin
 * bottom-left). Scope centre is passed as u_scopeCenter in the same
 * coordinate system.
 */
#version 330 core

out vec4 fragColor;

uniform sampler2D u_phosphor;   // GL_R32F phosphor energy FBO
uniform vec2  u_scopeCenter;    // scope centre in GL viewport pixels (bottom-left origin)
uniform float u_scopeRadius;    // scope radius in pixels
uniform float u_gain;           // receiver gain [0,1] — scales brightness
uniform float u_bloomStep;      // UV step for bloom sample (≈ 2.5 / FBO_SIZE)
uniform float u_bloomStrength;  // additive blend weight for bloom

// P7 energy thresholds (match settings.h)
const float T_BLUE  = 0.82;
const float T_GREEN = 0.55;
const float T_YGREE = 0.22;
const float T_DARK  = 0.03;

// P7 colour anchors
const vec3 C_BLUE  = vec3(0.30, 0.70, 1.00);
const vec3 C_GREEN = vec3(0.05, 1.00, 0.30);
const vec3 C_YGREE = vec3(0.50, 1.00, 0.05);
const vec3 C_YELLW = vec3(0.70, 0.70, 0.00);
const vec3 C_BLACK = vec3(0.00, 0.00, 0.00);

vec3 p7Color(float e) {
    if (e >= T_BLUE)
        return mix(C_GREEN, C_BLUE,  (e - T_GREEN) / (T_BLUE  - T_GREEN));
    if (e >= T_GREEN)
        return mix(C_YGREE, C_GREEN, (e - T_YGREE) / (T_GREEN - T_YGREE));
    if (e >= T_YGREE)
        return mix(C_YELLW, C_YGREE, (e - T_DARK ) / (T_YGREE - T_DARK ));
    if (e >= T_DARK)
        return mix(C_BLACK, C_YELLW, e / T_DARK);
    return C_BLACK;
}

void main() {
    // Fragment position relative to scope centre
    vec2 delta = (gl_FragCoord.xy - u_scopeCenter) / u_scopeRadius;
    float dist = length(delta);

    if (dist > 1.0) {
        fragColor = vec4(0.0);   // outside scope circle — transparent black
        return;
    }

    // Map from PPI delta [-1,+1] to phosphor texture UV [0,1]
    // delta.x = east, delta.y = north (both y directions already match)
    vec2 uv = delta * 0.5 + 0.5;

    float energy = texture(u_phosphor, uv).r * u_gain;

    // Inline bloom: weighted box-filter over a 5×5 neighbourhood
    float bloom = 0.0;
    float wsum  = 0.0;
    for (int dx = -2; dx <= 2; dx++) {
        for (int dy = -2; dy <= 2; dy++) {
            float w = exp(-float(dx*dx + dy*dy) * 0.45);
            float e = texture(u_phosphor, uv + vec2(dx, dy) * u_bloomStep).r;
            bloom += e * w;
            wsum  += w;
        }
    }
    bloom = (bloom / wsum) * u_bloomStrength;

    float finalE = clamp(energy + bloom, 0.0, 1.0);
    vec3  col    = p7Color(finalE);

    // Soft-edge vignette at the scope boundary
    float edge  = smoothstep(1.0, 0.97, dist);
    fragColor   = vec4(col * edge, 1.0);
}
