// 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.
/// <remarks>
/// STRIDE_GRAPHICS_PROFILE: Macro - graphics profile level.
/// </remarks>

namespace Stride.Rendering.Images
{
    /// <summary>
    /// A reduction shader
    /// </summary>
    shader DepthMinMaxShader<bool TFirstPass> : ImageEffectShader
    {
        Texture2D<float> TextureMap;
        Texture2D<float2> TextureReduction;


        float max_not_1(float left, float right)
        {
            if (left == 1.0f) return right;
            if (right == 1.0f) return left;
            return max(left, right);
        }

        stage override float4 Shading()
        {
            if (TFirstPass)
            {
                float4 values;

#if STRIDE_GRAPHICS_PROFILE >= GRAPHICS_PROFILE_LEVEL_10_1
                values = TextureMap.Gather(LinearSampler, streams.TexCoord);
#else
                values.x = TextureMap.Sample(PointSampler, streams.TexCoord, int2(-1, 0)).r;
                values.y = TextureMap.Sample(PointSampler, streams.TexCoord, int2(0, 0)).r;
                values.z = TextureMap.Sample(PointSampler, streams.TexCoord, int2(0, -1)).r;
                values.w = TextureMap.Sample(PointSampler, streams.TexCoord, int2(-1, -1)).r;
#endif
                // TODO: do a simple sort for 4 values quicker than min/max
                var minValue = min(min(values[0], values[1]), min(values[2], values[3]));
                var maxValue = max_not_1(max_not_1(values[0], values[1]), max_not_1(values[2], values[3]));

                return float4(minValue, maxValue, 0, 0);
            }
            else
            {
                float4 minValues, maxValues;

#if STRIDE_GRAPHICS_PROFILE >= GRAPHICS_PROFILE_LEVEL_11_0
                minValues = TextureReduction.GatherRed(LinearSampler, streams.TexCoord);
                maxValues = TextureReduction.GatherGreen(LinearSampler, streams.TexCoord);
#else
                float2 value0 = TextureReduction.Sample(PointSampler, streams.TexCoord, int2(-1, 0)).rg;
                float2 value1 = TextureReduction.Sample(PointSampler, streams.TexCoord, int2(0, 0)).rg;
                float2 value2 = TextureReduction.Sample(PointSampler, streams.TexCoord, int2(0, -1)).rg;
                float2 value3 = TextureReduction.Sample(PointSampler, streams.TexCoord, int2(-1, -1)).rg;
                minValues = float4(value0.r, value1.r, value2.r, value3.r);
                maxValues = float4(value0.g, value1.g, value2.g, value3.g);
#endif

                // TODO: do a simple sort for 4 values quicker than min/max
                var minValue = min(min(minValues[0], minValues[1]), min(minValues[2], minValues[3]));
                var maxValue = max_not_1(max_not_1(maxValues[0], maxValues[1]), max_not_1(maxValues[2], maxValues[3]));

                return float4(minValue, maxValue, 0, 0);
            }
        }
    };
}
