#version 450
layout(location = 0) in vec2 vUV;
layout(location = 1) in float vShade;
layout(location = 2) in vec3 vWorld;

layout(std140, binding = 0) uniform Globals {
    mat4  uMVP;
    mat4  uModel;
    int   uTextured;
    float uLayer;
    vec4  uColor;
    vec3  uAccent;
    int   uPattern;
    float uLight;
    vec3  uFog;
    float uFogAmt;
    int   uDynLightCount;
    vec4  uDynLightPosRadius0;
    vec4  uDynLightPosRadius1;
    vec4  uDynLightPosRadius2;
    vec4  uDynLightPosRadius3;
    vec4  uDynLightColor0;
    vec4  uDynLightColor1;
    vec4  uDynLightColor2;
    vec4  uDynLightColor3;
};
layout(binding = 1) uniform sampler2DArray uAtlas;
layout(binding = 2) uniform sampler2D uEntityTexture;

layout(location = 0) out vec4 FragColor;

vec3 pointLight(vec3 p, vec4 posRadius, vec4 colorIntensity) {
    vec3 d = p - posRadius.xyz;
    float a = max(0.0, 1.0 - dot(d, d) / max(posRadius.w * posRadius.w, 0.001));
    return colorIntensity.rgb * (colorIntensity.a * a * a);
}

vec3 dynamicLighting(vec3 p) {
    vec3 l = vec3(0.0);
    if (uDynLightCount > 0) l += pointLight(p, uDynLightPosRadius0, uDynLightColor0);
    if (uDynLightCount > 1) l += pointLight(p, uDynLightPosRadius1, uDynLightColor1);
    if (uDynLightCount > 2) l += pointLight(p, uDynLightPosRadius2, uDynLightColor2);
    if (uDynLightCount > 3) l += pointLight(p, uDynLightPosRadius3, uDynLightColor3);
    return min(l, vec3(2.0));
}

float hash(vec2 p) {
    return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453);
}

vec3 mobPattern(vec3 base, vec3 accent) {
    vec2 uv = vUV;
    vec2 cell = floor(uv * 8.0);
    float n = hash(cell + vec2(float(uPattern) * 13.0, 7.0));
    if (uPattern == 1) {
        float spot = smoothstep(0.48, 0.50, hash(cell) - distance(fract(uv * 4.0), vec2(0.5)) * 0.85);
        return mix(base, accent, spot);
    }
    if (uPattern == 2) {
        float fleece = 0.75 + 0.25 * hash(cell);
        return mix(base * fleece, accent, 0.18 * hash(floor(uv * 14.0)));
    }
    if (uPattern == 3) {
        float stripe = step(0.56, fract(uv.y * 7.0 + hash(vec2(floor(uv.x * 5.0), 3.0)) * 0.35));
        return mix(base, accent, stripe * 0.65);
    }
    if (uPattern == 4) {
        float band = step(0.82, fract(uv.y * 5.0));
        float joint = step(0.78, fract(uv.x * 4.0));
        return mix(base, accent, max(band, joint) * 0.45);
    }
    if (uPattern == 5) {
        float mottled = hash(cell);
        return mix(base * (0.78 + mottled * 0.28), accent, smoothstep(0.62, 0.9, mottled) * 0.55);
    }
    if (uPattern == 6) {
        float core = 1.0 - smoothstep(0.08, 0.34, distance(fract(uv * 4.0), vec2(0.5)));
        return mix(base, accent, core * 0.4) * (0.88 + hash(cell) * 0.18);
    }
    if (uPattern == 7) {
        float flame = smoothstep(0.18, 0.95, uv.y + sin(uv.x * 18.0) * 0.08);
        return mix(accent, base, flame);
    }
    return base * (0.92 + 0.12 * n);
}

void main() {
    vec4 base = uTextured == 1 ? texture(uAtlas, vec3(vUV, uLayer))
              : uTextured == 2 ? texture(uEntityTexture, vUV)
                                : vec4(mobPattern(uColor.rgb, uAccent), uColor.a);
    if (base.a < 0.3) discard;
    vec3 c = base.rgb * vShade * uLight;
    if (uDynLightCount > 0) {
        vec3 dyn = dynamicLighting(vWorld);
        c = max(c, base.rgb * vShade * dyn);
        c += base.rgb * vShade * dyn * 0.08;
    }
    c = mix(c, uFog, uFogAmt);
    FragColor = vec4(c, base.a);
}
