#include "ShaderApiReflectionSupport.hlsl"

#ifndef UNSLOW_SHADER_BASICS_LESSON15_FUNCTIONS_INCLUDED
#define UNSLOW_SHADER_BASICS_LESSON15_FUNCTIONS_INCLUDED

/// <funchints>
///     <sg:ProviderKey>UNSLOW.ShaderBasics.Lesson15.Branch</sg:ProviderKey>
///     <sg:DisplayName>Branch Color</sg:DisplayName>
///     <sg:ReturnDisplayName>Color</sg:ReturnDisplayName>
///     <sg:SearchCategory>UNSLOW/Shader Basics/Lesson 15</sg:SearchCategory>
///     <sg:SearchTerms>Branch, If, HLSL</sg:SearchTerms>
/// </funchints>
/// <paramhints name="uv">
///     <UV />
///     <Default>UV0</Default>
/// </paramhints>
UNITY_EXPORT_REFLECTION
float3 Lesson15Branch(float2 uv)
{
    float boundary = 0.5 + sin(uv.y * 12.0) * 0.08;

    if (uv.x < boundary)
        return float3(0.04, 0.22, 0.38);

    return float3(0.95, 0.38, 0.08);
}

/// <funchints>
///     <sg:ProviderKey>UNSLOW.ShaderBasics.Lesson15.Loop</sg:ProviderKey>
///     <sg:DisplayName>Bounded Wave Loop</sg:DisplayName>
///     <sg:ReturnDisplayName>Color</sg:ReturnDisplayName>
///     <sg:SearchCategory>UNSLOW/Shader Basics/Lesson 15</sg:SearchCategory>
///     <sg:SearchTerms>Loop, For, Break, HLSL</sg:SearchTerms>
/// </funchints>
/// <paramhints name="uv">
///     <UV />
///     <Default>UV0</Default>
/// </paramhints>
/// <paramhints name="iterations">
///     <sg:DisplayName>Iterations</sg:DisplayName>
///     <sg:Range>1, 8</sg:Range>
///     <sg:Default>5</sg:Default>
/// </paramhints>
UNITY_EXPORT_REFLECTION
float3 Lesson15Loop(float2 uv, float iterations)
{
    int count = clamp((int)round(iterations), 1, 8);
    float2 p = uv - 0.5;
    float waves = 0.0;

    [loop]
    for (int i = 0; i < 8; i++)
    {
        if (i >= count)
            break;

        float angle = i * 2.39996323;
        float2 direction = float2(cos(angle), sin(angle));
        waves += sin(dot(p, direction) * (18.0 + i * 2.0) + i * 1.3);
    }

    waves = waves * (0.5 / count) + 0.5;
    float band = smoothstep(0.35, 0.65, waves);
    return lerp(float3(0.06, 0.08, 0.22), float3(0.20, 0.90, 0.72), band);
}

float Lesson15SphereDistance(float3 position)
{
    return length(position) - 0.72;
}

/// <funchints>
///     <sg:ProviderKey>UNSLOW.ShaderBasics.Lesson15.RayMarch</sg:ProviderKey>
///     <sg:DisplayName>Simple Ray March</sg:DisplayName>
///     <sg:ReturnDisplayName>Color</sg:ReturnDisplayName>
///     <sg:SearchCategory>UNSLOW/Shader Basics/Lesson 15</sg:SearchCategory>
///     <sg:SearchTerms>Ray Marching, SDF, Loop, Break</sg:SearchTerms>
/// </funchints>
/// <paramhints name="uv">
///     <UV />
///     <Default>UV0</Default>
/// </paramhints>
UNITY_EXPORT_REFLECTION
float3 Lesson15RayMarch(float2 uv)
{
    float2 screen = (uv - 0.5) * 2.0;
    float3 rayOrigin = float3(0.0, 0.0, -2.4);
    float3 rayDirection = normalize(float3(screen, 1.7));
    float travel = 0.0;
    bool hit = false;

    [loop]
    for (int step = 0; step < 32; step++)
    {
        float3 position = rayOrigin + rayDirection * travel;
        float distanceToSurface = Lesson15SphereDistance(position);

        if (distanceToSurface < 0.002)
        {
            hit = true;
            break;
        }

        travel += distanceToSurface;
        if (travel > 5.0)
            break;
    }

    if (!hit)
        return float3(0.015, 0.02, 0.05);

    float3 hitPosition = rayOrigin + rayDirection * travel;
    float3 normal = normalize(hitPosition);
    float lighting = saturate(dot(normal, normalize(float3(-0.4, 0.7, -0.6))));
    return lerp(float3(0.04, 0.10, 0.22), float3(0.35, 0.85, 1.0), lighting);
}

#endif
