#include "ShaderApiReflectionSupport.hlsl"

#ifndef UNSLOW_SHADER_BASICS_BOX_BLUR_INCLUDED
#define UNSLOW_SHADER_BASICS_BOX_BLUR_INCLUDED

/// <funchints>
///     <sg:ProviderKey>UNSLOW.ShaderBasics.RepeatedBoxBlur</sg:ProviderKey>
///     <sg:DisplayName>Repeated 3x3 Box Blur</sg:DisplayName>
///     <sg:ReturnDisplayName>Color</sg:ReturnDisplayName>
///     <sg:SearchCategory>UNSLOW/Shader Basics/Blur</sg:SearchCategory>
///     <sg:SearchTerms>Blur, Repeat, Kernel, Texel Size, Sampling</sg:SearchTerms>
/// </funchints>
/// <paramhints name="inputTexture">
///     <sg:DisplayName>Input Texture</sg:DisplayName>
/// </paramhints>
/// <paramhints name="uv">
///     <UV />
///     <Default>UV0</Default>
/// </paramhints>
/// <paramhints name="repeatCount">
///     <sg:DisplayName>Repeat Count</sg:DisplayName>
/// </paramhints>
UNITY_EXPORT_REFLECTION
float4 RepeatedBoxBlur(UnityTexture2D inputTexture, float2 uv, float repeatCount)
{
    // A repeated 3x3 box blur is a convolution. Build its one-dimensional
    // weights by averaging the previous weights once per blur application.
    float weights[7] = { 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0 };
    int passes = clamp((int)round(repeatCount), 1, 3);

    [unroll]
    for (int iteration = 0; iteration < 3; iteration++)
    {
        if (iteration >= passes)
            break;

        float nextWeights[7];
        [unroll]
        for (int i = 0; i < 7; i++)
        {
            float value = weights[i];
            if (i > 0)
                value += weights[i - 1];
            if (i < 6)
                value += weights[i + 1];
            nextWeights[i] = value / 3.0;
        }

        [unroll]
        for (int tap = 0; tap < 7; tap++)
            weights[tap] = nextWeights[tap];
    }

    // The 2D kernel is the product of the horizontal and vertical weights.
    // This samples the source texture only once per offset. With the lesson's
    // Repeat wrap mode, it matches blurring each previous result in sequence.
    float4 color = 0.0;
    [loop]
    for (int y = -passes; y <= passes; y++)
    {
        [loop]
        for (int x = -passes; x <= passes; x++)
        {
            float weight = weights[x + 3] * weights[y + 3];
            float2 offset = float2(x, y) * inputTexture.texelSize.xy;
            color += inputTexture.Sample(inputTexture.samplerstate, uv + offset) * weight;
        }
    }

    return color;
}

#endif
