#version 410 core
out vec4 FragColor;
in vec2 vUV;

// --- hash / noise using integer cell coords ---
uint wang_hash(uint s){
    s = (s ^ 61u) ^ (s >> 16u);
    s *= 9u;
    s = s ^ (s >> 4u);
    s *= 0x27d4eb2du;
    s = s ^ (s >> 15u);
    return s;
}

float randFromCell(ivec2 ip) {
    uint x = uint(ip.x);
    uint y = uint(ip.y);
    return float(wang_hash(x + y * 374761393u) & 0x00FFFFFFu) / float(0x01000000);
}

float noise(in vec2 p) {
    vec2 i = floor(p);
    vec2 f = fract(p);
    vec2 u = f * f * (3.0 - 2.0 * f);

    ivec2 I = ivec2(i);
    float a = randFromCell(I + ivec2(0,0));
    float b = randFromCell(I + ivec2(1,0));
    float c = randFromCell(I + ivec2(0,1));
    float d = randFromCell(I + ivec2(1,1));

    return mix(mix(a, b, u.x), mix(c, d, u.x), u.y);
}

float fbm(in vec2 p) {
    float total = 0.0;
    float amplitude = 0.5;
    float freq = 1.0;
    for (int i = 0; i < 6; ++i) {
        total += amplitude * noise(p * freq);
        freq *= 2.0;
        amplitude *= 0.5;
    }
    return total;
}

// seamless tiling function (fixed: do NOT re-multiply by tileSize at the end)
vec2 tileUV(vec2 uv, float tileSize) {
    float x = uv.x * tileSize;
    float y = uv.y * tileSize;
    float rx = cos(x * 6.2831853);
    float ry = sin(x * 6.2831853);
    float rz = cos(y * 6.2831853);
    float rw = sin(y * 6.2831853);
    return vec2(rx * 0.5 + rz * 0.5, ry * 0.5 + rw * 0.5);
}

void main() {
    vec2 uv = vUV;

    // test-friendly values
    float tile = 2.0;
    float a = fbm(tileUV(uv, tile) * 1.0);
    float b = fbm(tileUV(uv + vec2(10.0, 7.0), tile) * 2.0) * 0.6;
    float c = fbm(tileUV(uv + vec2(3.0, 14.0), tile) * 4.0) * 0.3;
    float aggregate = clamp(a * 0.7 + b + c, 0.0, 1.0);

    float angle = 0.3;
    vec2 dir = normalize(vec2(cos(angle), sin(angle)));
    float streakFreq = 0.7;
    float s = fbm(tileUV(uv * streakFreq, tile) * dir);
    float streak = smoothstep(0.1, 0.9, s) * 0.05;

    float dark = 0.12;
    float light = 0.28;
    float shade = mix(dark, light, aggregate);
    shade += streak;

    float rough = fbm(uv * 8.0) * 0.08;

    vec3 base = vec3(shade - rough);
    base += vec3(aggregate * 0.03);
    base = clamp(base, 0.0, 1.0);

    FragColor = vec4(base, 1.0);
}
