#pragma clang diagnostic ignored "-Wmissing-prototypes"

#include <metal_stdlib>
#include <simd/simd.h>

using namespace metal;

// Implementation of the GLSL mod() function, which is slightly different than Metal fmod()
template<typename Tx, typename Ty>
inline Tx mod(Tx x, Ty y)
{
    return x - y * floor(x / y);
}

struct main0_out
{
    float4 out_color [[color(0)]];
};

struct main0_in
{
    float4 f_color [[user(locn0)]];
    float2 f_local_or_uv [[user(locn1)]];
    float4 f_params [[user(locn2)]];
    float4 f_params2 [[user(locn3)]];
    uint f_flags [[user(locn4)]];
    float4 f_uv_rect [[user(locn6), flat]];
    uint4 f_effects [[user(locn7)]];
};

static inline __attribute__((always_inline))
float sdRoundedBox(thread const float2& p, thread const float2& b, thread const float4& r)
{
    float2 _48;
    if (p.x > 0.0)
    {
        _48 = r.xy;
    }
    else
    {
        _48 = r.zw;
    }
    float2 rxy = _48;
    float _62;
    if (p.y > 0.0)
    {
        _62 = rxy.x;
    }
    else
    {
        _62 = rxy.y;
    }
    float rr = _62;
    float2 q = abs(p) - b;
    if (rr == 0.0)
    {
        return fast::max(q.x, q.y);
    }
    q += float2(rr);
    return (fast::min(fast::max(q.x, q.y), 0.0) + length(fast::max(q, float2(0.0)))) - rr;
}

static inline __attribute__((always_inline))
float sdRegularPolygon(thread const float2& p, thread const float& r, thread const float& n)
{
    float an = 3.1415927410125732421875 / n;
    float bn = mod(precise::atan2(p.y, p.x), 2.0 * an) - an;
    return (length(p) * cos(bn)) - r;
}

static inline __attribute__((always_inline))
float sdEllipseApprox(thread const float2& p, thread const float2& ab)
{
    float k0 = length(p / ab);
    float k1 = length(p / (ab * ab));
    return (k0 * (k0 - 1.0)) / k1;
}

static inline __attribute__((always_inline))
float4 gradient_2color(thread const float4& start_color, thread const float4& end_color, thread const float& t)
{
    return mix(start_color, end_color, float4(fast::clamp(t, 0.0, 1.0)));
}

static inline __attribute__((always_inline))
float sdf_alpha(thread const float& d, thread const float& h)
{
    return 1.0 - smoothstep(-h, h, d);
}

fragment main0_out main0(main0_in in [[stage_in]], texture2d<float> tex [[texture(0)]], sampler texSmplr [[sampler(0)]])
{
    main0_out out = {};
    uint kind = in.f_flags & 255u;
    uint flags = (in.f_flags >> 8u) & 255u;
    if (kind == 0u)
    {
        float4 t = tex.sample(texSmplr, in.f_local_or_uv);
        float _195 = t.w;
        float4 _197 = t;
        float3 _199 = _197.xyz * _195;
        t.x = _199.x;
        t.y = _199.y;
        t.z = _199.z;
        out.out_color = in.f_color * t;
        return out;
    }
    float d = 1000000015047466219876688855040.0;
    float h = 0.5;
    float2 half_size_ppx = in.f_params.xy;
    float2 p_local_ppx = in.f_local_or_uv;
    if (kind == 1u)
    {
        float4 corner_radii_ppx = float4(in.f_params.zw, in.f_params2.xy);
        h = in.f_params2.z;
        float2 param = p_local_ppx;
        float2 param_1 = half_size_ppx;
        float4 param_2 = corner_radii_ppx;
        d = sdRoundedBox(param, param_1, param_2);
    }
    else
    {
        if (kind == 2u)
        {
            float radius_ppx = in.f_params.x;
            float sides = in.f_params.y;
            h = in.f_params.z;
            float2 param_3 = p_local_ppx;
            float param_4 = radius_ppx;
            float param_5 = sides;
            d = sdRegularPolygon(param_3, param_4, param_5);
            half_size_ppx = float2(radius_ppx);
        }
        else
        {
            if (kind == 3u)
            {
                float2 radii_ppx = in.f_params.xy;
                h = in.f_params.z;
                float2 param_6 = p_local_ppx;
                float2 param_7 = radii_ppx;
                d = sdEllipseApprox(param_6, param_7);
                half_size_ppx = radii_ppx;
            }
            else
            {
                if (kind == 4u)
                {
                    float inner_radius_ppx = in.f_params.x;
                    float outer_radius_ppx = in.f_params.y;
                    float2 n_start = in.f_params.zw;
                    float2 n_end = in.f_params2.xy;
                    uint arc_bits = (flags >> 5u) & 3u;
                    h = in.f_params2.z;
                    float r = length(p_local_ppx);
                    d = fast::max(inner_radius_ppx - r, r - outer_radius_ppx);
                    if (arc_bits != 0u)
                    {
                        float d_start = dot(p_local_ppx, n_start);
                        float d_end = dot(p_local_ppx, n_end);
                        float _338;
                        if (arc_bits == 1u)
                        {
                            _338 = fast::max(d_start, d_end);
                        }
                        else
                        {
                            _338 = fast::min(d_start, d_end);
                        }
                        float d_wedge = _338;
                        d = fast::max(d, d_wedge);
                    }
                    half_size_ppx = float2(outer_radius_ppx);
                }
            }
        }
    }
    float grad_magnitude = fast::max(fwidth(d), 9.9999999747524270787835121154785e-07);
    d /= grad_magnitude;
    h /= grad_magnitude;
    float4 shape_color;
    if ((flags & 2u) != 0u)
    {
        float4 gradient_start = in.f_color;
        float4 gradient_end = unpack_unorm4x8_to_float(in.f_effects.x);
        if ((flags & 4u) != 0u)
        {
            float t_1 = length(p_local_ppx / half_size_ppx);
            float4 param_8 = gradient_start;
            float4 param_9 = gradient_end;
            float param_10 = t_1;
            shape_color = gradient_2color(param_8, param_9, param_10);
        }
        else
        {
            float2 direction = float2(as_type<half2>(in.f_effects.z));
            float t_2 = (dot(p_local_ppx / half_size_ppx, direction) * 0.5) + 0.5;
            float4 param_11 = gradient_start;
            float4 param_12 = gradient_end;
            float param_13 = t_2;
            shape_color = gradient_2color(param_11, param_12, param_13);
        }
    }
    else
    {
        if ((flags & 1u) != 0u)
        {
            float4 uv_rect = in.f_uv_rect;
            float2 local_uv = ((p_local_ppx / half_size_ppx) * 0.5) + float2(0.5);
            float2 uv = mix(uv_rect.xy, uv_rect.zw, local_uv);
            shape_color = in.f_color * tex.sample(texSmplr, uv);
        }
        else
        {
            shape_color = in.f_color;
        }
    }
    if ((flags & 8u) != 0u)
    {
        float4 ol_color = unpack_unorm4x8_to_float(in.f_effects.y);
        float ol_width = float2(as_type<half2>(in.f_effects.w)).x / grad_magnitude;
        float param_14 = d;
        float param_15 = h;
        float fill_cov = sdf_alpha(param_14, param_15);
        float param_16 = d - ol_width;
        float param_17 = h;
        float total_cov = sdf_alpha(param_16, param_17);
        float outline_cov = fast::max(total_cov - fill_cov, 0.0);
        float3 rgb_pm = ((shape_color.xyz * shape_color.w) * fill_cov) + ((ol_color.xyz * ol_color.w) * outline_cov);
        float alpha_pm = (shape_color.w * fill_cov) + (ol_color.w * outline_cov);
        out.out_color = float4(rgb_pm, alpha_pm);
    }
    else
    {
        float param_18 = d;
        float param_19 = h;
        float alpha = sdf_alpha(param_18, param_19);
        out.out_color = float4((shape_color.xyz * shape_color.w) * alpha, shape_color.w * alpha);
    }
    return out;
}

