#include "depth_normal.fsh"
precision mediump int;

#define _GLSL_FS

#include "VLBCommon.sh"

void main() {

    float outsideBeam = vs_camPosObjectSpace_outsideBeam.w;

#if OPTIM_VS
    float intensity = vs_intensity;
#else
    float intensity = 1.0;
#endif // OPTIM_VS

    float pixDistFromSource = length(vs_posObjectSpace.z);
    
    // additional clipping plane
    {
        float4 addClippingPlaneWS = VLB_GET_PROP(_AdditionalClippingPlaneWS);
        clip(DistanceToPlane(vs_posWorldSpace.xyz, addClippingPlaneWS));
    }

#if VLB_OCCLUSION_CLIPPING_PLANE
    {
        float4 clippingPlaneWS = VLB_GET_PROP(_DynamicOcclusionClippingPlaneWS);
        float distToClipPlane = DistanceToPlane(vs_posWorldSpace.xyz, clippingPlaneWS);
        clip(distToClipPlane);
        float fadeDistance = VLB_GET_PROP(_DynamicOcclusionClippingPlaneProps);
        intensity *= smoothstep(0.0, fadeDistance, distToClipPlane);
    }
#endif

    float3 cameraPosObjectSpace = vs_camPosObjectSpace_outsideBeam.xyz;

    // Vector Camera to current Pixel, in object space and normalized
    float3 vecCamToPixOSN = ComputeVectorCamToPixOSN(vs_posObjectSpaceNonSkewed.xyz, cameraPosObjectSpace);

#if !OPTIM_VS
    // Blend inside and outside
    float vecCamToPixDotZ = dot(vecCamToPixOSN, float3(0, 0, 1));
    // float factorNearAxisZ = abs(vecCamToPixDotZ);
#endif

    // DEPTH BLEND
#if VLB_DEPTH_BLEND
    {
        float depthBlendDistance = VLB_GET_PROP(_DepthBlendDistance);
        
    #if FIX_DISABLE_DEPTH_BLEND_WITH_OBLIQUE_PROJ
        // disable depth sampling with oblique projection
        float3 nearPlaneWS = _CameraWorldClipPlanes[4].xyz;
        float3 farPlaneWS = _CameraWorldClipPlanes[5].xyz;
        float dotNearFar = abs(dot(nearPlaneWS, farPlaneWS));
        depthBlendDistance *= isEqualOrGreater(dotNearFar, 0.99);
    #endif // FIX_DISABLE_DEPTH_BLEND_WITH_OBLIQUE_PROJ

        // we disable blend factor when the pixel is near the light source,
        // to prevent from blending with the light source model geometry (like the flashlight model).
        float depthBlendStartDistFromSource = depthBlendDistance;
        float pixDistFromSourceNormalized = invLerpClamped(0.0, depthBlendStartDistFromSource, pixDistFromSource);
        float depthBlendDist = depthBlendDistance * pixDistFromSourceNormalized;
        float depthBlendFactor = DepthFade_PS_BlendDistance(vs_projPos, depthBlendDist);
        depthBlendFactor = lerp(depthBlendFactor, 1.0, isEqualOrGreater(0.0, depthBlendDistance));
        depthBlendFactor = lerpClamped(1.0, depthBlendFactor, pixDistFromSourceNormalized * 900.0); // prevent artifacts when cap geometry is too close from some geometry
        intensity *= depthBlendFactor;

    #if DEBUG_DEPTH_MODE == DEBUG_VALUE_DEPTHBUFFER
        fs_color = float4(SampleSceneZ_Eye(vs_projPos) * _ProjectionParams.w);
        return;
    #elif DEBUG_DEPTH_MODE == DEBUG_VALUE_DEPTHBLEND
        fs_color = float4(depthBlendFactor);
        return;
    #endif
    }
#endif

#if VLB_PS_DEPTH_TEST && !VLB_DEPTH_BLEND
    DepthTestClip(vs_projPos);
#endif // VLB_PS_DEPTH_TEST

    float3 posViewSpace = vs_posViewSpace_extraData.xyz;

#if !OPTIM_VS
    float pixDistFromSourceTilted = GetTiltDistanceFactor(vs_posObjectSpace);
    {
        float isCap = vs_posViewSpace_extraData.w;

        // no intensity for cap if _DrawCap = 0
        intensity *= isEqualOrGreater(VLB_GET_PROP(_DrawCap), isCap - 0.00001);

        // Treat Cap a special way: cap is only visible from inside
        intensity *= 1.0 - outsideBeam * isCap; // AKA if (outsideBeam == 1 && isCap == 1) intensity = 0

        // boost factor
        float boostFactor = ComputeBoostFactor(pixDistFromSource, outsideBeam, isCap);

        // fresnel
        intensity *= ComputeFresnel(vs_posObjectSpaceNonSkewed, vecCamToPixOSN, outsideBeam, boostFactor);

        // fade out
        intensity *= VLB_GET_PROP(_FadeOutFactor);

        // attenuation
        float3 distancesFallOff = VLB_GET_PROP(_DistanceFallOff);
        intensity *= ComputeAttenuation(pixDistFromSourceTilted, distancesFallOff.x, distancesFallOff.y, VLB_GET_PROP(_AttenuationLerpLinearQuad));

        // smooth blend between inside and outside geometry depending of View Direction
        intensity *= ComputeInOutBlending(vecCamToPixDotZ, outsideBeam);
    }
#elif !OPTIM_VS_FRESNEL_VS // && OPTIM_VS
    {
        float boostFactor = vs_posViewSpace_extraData.w;
        // compute fresnel in fragment shader to keep good quality even with low tessellation
        intensity *= ComputeFresnel(vs_posObjectSpaceNonSkewed, vecCamToPixOSN, outsideBeam, boostFactor);
    }
#endif // !OPTIM_VS_FRESNEL_VS && OPTIM_VS

    // fade when too close to camera factor
    {
        const float fadeWithCameraEnabled = 1.0; // fading according to camera eye position doesn't make sense with ortho camera
        intensity *= ComputeFadeWithCamera(posViewSpace, fadeWithCameraEnabled);
    }

#if DEBUG_BLEND_INSIDE_OUTSIDE
    float DBGvecCamToPixDotZ = dot(vecCamToPixOSN, float3(0, 0, 1));
    fs_color = lerp(float4(1, 0, 0, 1), float4(0, 1, 0, 1), ComputeInOutBlending(DBGvecCamToPixDotZ, outsideBeam));
    return;
#endif // DEBUG_BLEND_INSIDE_OUTSIDE

    // Do not fill color.rgb only, because of performance drops on android
#if !OPTIM_VS
    half4 color = ComputeColor(pixDistFromSourceTilted, outsideBeam);
#else
    half4 color = vs_color;
#endif

#if VLB_ALPHA_AS_BLACK
    color *= intensity;
#else
    color.a *= intensity;
#endif

    fs_color = color;
}
