/*
====================================================================
  SXGG: Realis — Shader ultra-realistica per Minecraft
  Autore : Samax.GG
  File   : lib/pbr.glsl
  Modulo : 2 — BRDF Cook-Torrance (Metalness/Roughness, LabPBR)

  Decodifica LabPBR (texture _s):
    r = perceptual smoothness  -> roughness = (1-r)^2
    g = f0 / metallo (>= 230/255 = metallo)
    b = porosità / subsurface
    a = emissione (0..254)/255, 1.0 = nessuna
====================================================================
*/

#ifndef PBR_GLSL
#define PBR_GLSL

struct Material {
    vec3  albedo;
    float roughness;
    float f0;          // riflettanza a incidenza zero (dielettrici)
    float metalness;
    float emission;    // 0..1
    float porosity;
};

Material decodeLabPBR(vec4 specularTex, vec3 albedo) {
    Material mat;
    mat.albedo    = albedo;
    float smoothness = specularTex.r;
    mat.roughness = (1.0 - smoothness) * (1.0 - smoothness);
    mat.roughness = max(mat.roughness, 0.02);

    mat.metalness = step(229.5 / 255.0, specularTex.g);
    mat.f0        = mix(specularTex.g, 0.04, step(specularTex.g, 0.001));
    mat.porosity  = specularTex.b;
    mat.emission  = specularTex.a < 1.0 ? specularTex.a : 0.0;
    return mat;
}

// --- GGX / Trowbridge-Reitz normal distribution ---
float distributionGGX(float NdotH, float roughness) {
    float a  = roughness * roughness;
    float a2 = a * a;
    float d  = NdotH * NdotH * (a2 - 1.0) + 1.0;
    return a2 / max(PI * d * d, EPSILON);
}

// --- Smith-Schlick geometry ---
float geometrySmith(float NdotV, float NdotL, float roughness) {
    float k  = (roughness + 1.0);
    k = k * k * 0.125;
    float g1 = NdotV / (NdotV * (1.0 - k) + k);
    float g2 = NdotL / (NdotL * (1.0 - k) + k);
    return g1 * g2;
}

// --- Fresnel-Schlick ---
vec3 fresnelSchlick(float cosTheta, vec3 F0) {
    return F0 + (1.0 - F0) * pow(saturate(1.0 - cosTheta), 5.0);
}

/*
  BRDF completa: ritorna la luce riflessa per una singola sorgente.
  N,V,L in view space, normalizzati. lightColor già attenuato.
*/
vec3 cookTorrance(vec3 N, vec3 V, vec3 L, Material mat, vec3 lightColor) {
    float NdotL = dot(N, L);
    if (NdotL <= 0.0) return vec3(0.0);

    vec3  H     = normalize(V + L);
    float NdotV = max(dot(N, V), EPSILON);
    float NdotH = max(dot(N, H), 0.0);
    float VdotH = max(dot(V, H), 0.0);

    // F0: dielettrici usano f0 scalare, metalli l'albedo
    vec3 F0 = mix(vec3(mat.f0), mat.albedo, mat.metalness);

    float D = distributionGGX(NdotH, mat.roughness);
    float G = geometrySmith(NdotV, NdotL, mat.roughness);
    vec3  F = fresnelSchlick(VdotH, F0);

    vec3 specular = (D * G * F) / max(4.0 * NdotV * NdotL, EPSILON);

    // Energia diffusa: solo la parte non riflessa, zero per i metalli
    vec3 kD = (1.0 - F) * (1.0 - mat.metalness);
    vec3 diffuse = kD * mat.albedo / PI;

    return (diffuse + specular) * lightColor * NdotL;
}

#endif // PBR_GLSL
