// 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.Images
{

    /// <summary>
    /// Combines the different blur levels depending on the pixel's CoC. (Front area only.)
    /// </summary>
    shader CombineFrontCoCShader<int TLevelCount> : ImageEffectShader
    {

        stage override float4 Shading()
        {

            // Fetch all our levels
            float4 colorLevels[8];

			// Note: Manually unrolled until better HLSL2GLSL support
			if (TLevelCount >= 1)
	            colorLevels[0] = Texture2.Sample(LinearSampler, streams.TexCoord).rgba;
			if (TLevelCount >= 2)
				colorLevels[1] = Texture3.Sample(LinearSampler, streams.TexCoord).rgba;
			if (TLevelCount >= 3)
				colorLevels[2] = Texture4.Sample(LinearSampler, streams.TexCoord).rgba;
			if (TLevelCount >= 4)
				colorLevels[3] = Texture5.Sample(LinearSampler, streams.TexCoord).rgba;
			if (TLevelCount >= 5)
				colorLevels[4] = Texture6.Sample(LinearSampler, streams.TexCoord).rgba;
			if (TLevelCount >= 6)
				colorLevels[5] = Texture7.Sample(LinearSampler, streams.TexCoord).rgba;
			if (TLevelCount >= 7)
				colorLevels[6] = Texture8.Sample(LinearSampler, streams.TexCoord).rgba;
			if (TLevelCount >= 8)
				colorLevels[7] = Texture9.Sample(LinearSampler, streams.TexCoord).rgba;


            float4 result = float4(0.0, 0.0, 0.0, 0.0);

            // Gets the CoC of the current pixel
            float CoC = Texture0.Sample(LinearSampler, streams.TexCoord).x;

            // A front object has by default its in-focus color. 
            if (CoC < 0) result = colorLevels[0];

            // Alpha blend all the layers in the good order
            // TODO we should be more selective and only blend the layer closest to the pixel CoC
            [unroll]
            for (int k = 1; k < TLevelCount; k++) 
            {
                float4 layerColor = colorLevels[k];
                float newAlpha = layerColor.a + result.a * (1.0 - layerColor.a);
                float3 newRGB = float4(0.0, 0.0, 0.0, 0.0);
                if (newAlpha > 0) 
                {
                    newRGB = (layerColor.rgb * layerColor.a + result.rgb * result.a * (1.0 - layerColor.a)) / newAlpha;
                }
                result = float4(newRGB, newAlpha);
            }

            // Need pre-multiply alpha for the blending with the render target. 
            result.rgb *= result.a;

            return result;
        }
    };
}
