// 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.
/// <summary>
/// Samples a texture with a custom sampler and fix texture coordinates offset and scale.
/// </summary>
/// <remarks>
/// TTexture: generic Texture2D - the texture to sample.
/// TStream: generic Semantic - the texcoord index semantic used to sample the texture.
/// TScale: generic LinkType - the float2 key for scaling factor of the texture coordinates.
/// TOffset: generic LinkType - the float2 key for texture coordinates offset.
/// TSampler: generic SamplerState - the custom sampler.
/// </remarks>
shader ComputeColorTextureScaledOffsetDynamicSamplerRandomUV<LinkType TTextureName, 
                                             Semantic TStream, 
                                             LinkType TSampler, 
                                             MemberName TRgba, 
                                             LinkType TScale, 
                                             LinkType TOffset> : ComputeColor, 
                                                               DynamicTexture<TTextureName, PerMaterial>, 
                                                               DynamicSampler<TSampler, PerMaterial>, 
                                                               DynamicTextureStream<TStream>
{
    cbuffer PerMaterial
    {
        [Link("TScale")]
        stage float2 scale;

        [Link("TOffset")]
        stage float2 offset;
    }
    
    //------------------------------------------------------------------------------
    // Gererate pseudorandom number
    //------------------------------------------------------------------------------
    float Random(in float2 uv)
    {
        float2 noise = (frac(sin(dot(uv,float2(12.9898,78.233)*2.0)) * 43758.5453));
        return abs(noise.x + noise.y) * 0.5;
    }

    //------------------------------------------------------------------------------
    // Gererate texture coordinates for random placement
    //------------------------------------------------------------------------------
    float2 RandomUV(in float2 uv)
    {
        const uint NUM_PATTERNS = 2 * 2 * 4 * 4 * 4;

        uint pattern = (uint)(Random(floor(uv)) * (float)NUM_PATTERNS) % NUM_PATTERNS;
        float2 result = frac(uv);

        // flip
        if ((uint)(pattern % 2) != 0)
        {
            result.x = 1.0f - result.x;
        }
        pattern /= 2;
        if ((uint)(pattern % 2) != 0)
        {
            result.y = 1.0f - result.y;
        }

        // rotate
        pattern /= 2;
        if (pattern % 4 == 1)
        {
            result = float2(result.y, 1.0f - result.x);
        }
        else if (pattern % 4 == 2)
        {
            result = float2(1.0f - result.y, result.x);
        }
        else if (pattern % 4 == 3)
        {
            result = 1.0f - result;
        }

        // offset
        pattern /= 4;
        result.x += (pattern % 4) * 0.25f;
        pattern /= 4;
        result.y += (pattern % 4) * 0.25f;

        return result;
    }

    override float4 Compute() {
        return Texture.Sample(Sampler, RandomUV(streams.TexCoord * scale + offset)).TRgba;
    }
};