// BVLE Voxels - Toping Pixel Shader (Phase 4.2)
// Vegetation: vertical gradient + up-biased lighting for stable grass look.
// Stone: classic Lambert + hemisphere ambient.

#include "voxelCommon.hlsli"

Texture2DArray<float4> materialTextures : register(t1);
SamplerState texSampler : register(s0);

struct PSInput {
    float4 position : SV_POSITION;
    float3 worldPos : WORLDPOS;
    float3 normal   : NORMAL;
    float  localHeight : LOCALHEIGHT;
    nointerpolation uint materialID : MATERIALID;
};

struct PSOutput {
    float4 color  : SV_TARGET0;
    float4 normal : SV_TARGET1;
};

[RootSignature(VOXEL_ROOTSIG)]
PSOutput main(PSInput input) {
    PSOutput output;
    float3 N = normalize(input.normal);
    float tiling = textureTiling;

    // Material texture index (materialID 1-5 → array layer 0-4)
    uint texIdx = clamp(input.materialID - 1u, 0u, 4u);

    // Triplanar sampling (same as voxel PS)
    float3 blend = abs(N);
    blend = blend / (blend.x + blend.y + blend.z + 0.001);

    float4 xSample = materialTextures.Sample(texSampler, float3(input.worldPos.yz * tiling, (float)texIdx));
    float4 ySample = materialTextures.Sample(texSampler, float3(input.worldPos.xz * tiling, (float)texIdx));
    float4 zSample = materialTextures.Sample(texSampler, float3(input.worldPos.xy * tiling, (float)texIdx));

    float3 texColor = (xSample.rgb * blend.x + ySample.rgb * blend.y + zSample.rgb * blend.z);

    float3 L = normalize(-sunDirection.xyz);

    // ── Material-dependent lighting ─────────────────────────────
    float3 lit;
    float hemiLerp = N.y * 0.5 + 0.5;
    float3 V = normalize(cameraPosition.xyz - input.worldPos);

    if (input.materialID == 3u) {
        // Stone: classic Lambert + hemisphere ambient
        float NdotL = max(dot(N, L), 0.0);
        float3 ambient = lerp(groundAmbient.rgb, skyAmbient.rgb, hemiLerp);
        lit = texColor * (sunColor.rgb * NdotL + ambient);
    } else {
        // ── Vegetation shading ──────────────────────────────────

        // Vertical gradient: dark green at base → lighter at tip
        float h = input.localHeight;  // 0=base, ~1=tip
        float3 baseColor = texColor * 0.55;  // darker at roots
        float3 tipColor  = texColor * 1.15;  // brighter at tips
        float3 grassColor = lerp(baseColor, tipColor, h);

        // Up-biased normal for stable lighting on thin geometry
        // Blend between actual normal and UP vector based on how "grassy" (non-stone)
        float3 lightN = normalize(lerp(N, float3(0, 1, 0), 0.65));
        float NdotL = dot(lightN, L);

        // Soft wrap lighting (half-Lambert)
        float halfLambert = NdotL * 0.5 + 0.5;
        float wrap = halfLambert * halfLambert;

        // Translucency: light passing through thin blades from behind
        float backLight = saturate(dot(V, L));
        float transAmount = (1.0 - saturate(NdotL)) * 0.5;
        float translucency = backLight * transAmount;

        // Hemisphere ambient, boosted for vegetation inter-reflection
        float3 ambient = lerp(groundAmbient.rgb, skyAmbient.rgb, lightN.y * 0.5 + 0.5) * 1.3;

        // Combine
        float3 diffuse = sunColor.rgb * (wrap * 0.85 + translucency * 0.35);
        lit = grassColor * (diffuse + ambient);
    }

    // ── Rim light (reduced on vegetation) ──
    float NdotV = saturate(dot(N, V));
    float rimScale = (input.materialID == 3u) ? 1.0 : 0.2;
    float rim = pow(1.0 - NdotV, rimParams.x) * rimParams.y * rimScale;
    lit += rimColor.rgb * rim;

    output.color = float4(lit, 1.0);
    output.normal = float4(N, 0.0);
    return output;
}
