precision highp float;

#define PI 3.14159265
#define EPSILON 0.001
#define RADIUS 40.

out vec4 FragColor;

in vec2 FragCoord;

uniform float u_RocketRow;
uniform vec2 u_Resolution;

uniform sampler2D u_FeedbackSampler;
uniform float r_FeedbackEffect;

uniform r_Cam {
    float fov;
    vec3 pos;
    vec3 target;
} cam;

float aspectRatio() {
    return u_Resolution.x / u_Resolution.y;
}

mat3 viewMatrix() {
    vec3 f = normalize(cam.target - cam.pos);
    vec3 s = normalize(cross(f, vec3(0., 1., 0.)));
    vec3 u = cross(s, f);
    return mat3(s, u, f);
}

vec3 cameraRay() {
    float c = tan((90. - cam.fov / 2.) * (PI / 180.));
    return normalize(vec3(FragCoord * vec2(aspectRatio(), 1.), c));
}

vec3 amigaTexture(vec2 pos, float n) {
    float l = clamp(sin(pos.x * n) * sin(pos.y * n) * 10000.0, 0.0, 1.0);
    return vec3(1.0, 0.6, 0.6) * l + (vec3(1.0, 1.0, 1.0) * (1.0 - l));
}

float waveTexture(vec2 pos) {
    pos.y *= sin(pos.y) * 0.2 + 0.8;
    float base = sin(pos.y + u_RocketRow * 0.1) * 10. - 9.;
    base *= sin(pos.x * 14. * PI + u_RocketRow * 0.33) * 2.2;

    pos.y += pos.x * 0.33;
    float mask = sin(pos.y * PI + u_RocketRow * 0.22) * 32. - 30.;
    mask = clamp(mask, 0., 1.);

    return clamp(base * mask, 0., 20.);
}

float tunnel(vec3 origin, vec3 direction) {
    float a = direction.x * direction.x + direction.y * direction.y;
    float b = 2.0 * (origin.x * direction.x + origin.y * direction.y);
    float c = origin.x * origin.x + origin.y * origin.y - RADIUS * RADIUS;
    float disc = b * b - 4.0 * a * c;
    float t = 0.0;
    if (disc < 0.0)
        return 1000000.0;
    else if (disc < EPSILON)
        return -b / (2.0 * a);
    else
        return min((-b + sqrt(disc)) / (2.0 * a), (-b - sqrt(disc)) / (2.0 * a));
}

void main() {
    vec3 ray = viewMatrix() * cameraRay();

    vec3 pos = cam.pos + ray * tunnel(cam.pos, ray);
    vec3 nml = normalize(vec3(vec2(0.), pos.z) - pos);
    vec2 uv = vec2(atan(pos.y, pos.x), pos.z / RADIUS);

    float light = max(dot(nml, -normalize(pos - cam.pos)), 0.);

    FragColor = vec4(light * amigaTexture(uv, 8.) * waveTexture(uv), 1.);

    uv = FragCoord * 0.98 * vec2(0.5) + vec2(0.499);
    FragColor += texture2D(u_FeedbackSampler, uv) * r_FeedbackEffect;
}
