// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp)
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.

namespace Stride.Rendering.Shadows
{
    /// <summary>
    /// Selects the shadow map and computes the shadow factor.
    /// </summary>
    internal shader ShadowMapReceiverPointParaboloid<int TLightCount> : ShadowMapGroup<PerDraw.Lighting>, ShadowMapFilterBase<PerDraw.Lighting>, PositionStream4, ShaderBaseStream
    {
        cbuffer PerDraw.Lighting
        {
            float4x4 View[TLightCount];
            float2 FaceOffsets[TLightCount];
            float2 BackfaceOffsets[TLightCount];
            float2 FaceSizes[TLightCount];
            float DepthBiases[TLightCount];
            float2 DepthParameters[TLightCount];
        };
        
        override float3 ComputeShadow(float3 position, int lightIndex)
        {
            float4 lightSpace = mul(float4(position, 1), View[lightIndex]);
            
            // Store length and normalize
            float distanceToLight = length(lightSpace.xyz);
            float3 intermediate = lightSpace.xyz / distanceToLight;
            
            // Project x/y coordinates on parabola
            intermediate.xy /= 1.0f + abs(intermediate.z);
            
            float2 depthParameters = DepthParameters[lightIndex];
            
            // Apply bias
            distanceToLight -= DepthBiases[lightIndex];

            // Scale distance to light depth buffer range 
            distanceToLight *= depthParameters.y;

            // Map from (-1,1) to (0,1)
            intermediate.xy = intermediate.xy * 0.5 + float2(0.5, 0.5);
            intermediate.y = 1.0f-intermediate.y;

            // Apply offset into atlas and size of a single face in the atlas
            float2 samplePosition = intermediate.xy * FaceSizes[lightIndex] + FaceOffsets[lightIndex];

            // Apply offset for the back side face
            [flatten]
            if(lightSpace.z < 0)
            {
                samplePosition += BackfaceOffsets[lightIndex];
            }
            
            // Compare distance to light to value inside of the shadow map
            float shadow = FilterShadow(samplePosition, distanceToLight);
            
            // Calculate thickness for SSS:
            float tempThickness = 999.9;    // No scattering for now.



            streams.thicknessWS = tempThickness;
            
            return(shadow);
        }
    };
}
