#include <metal_stdlib>
using namespace metal;

// shader f14bb57cd5c9cb77
// Shader dumped from BotW 208, using Cemu 2193a8c
// Based on f14bb57cd5c9cb77_00000000000003c9_ps.txt
// Used for: Removing/Restoring the native BotW World Anti-Aliasing
// implementation

constant float resX = float($width) / float($gameWidth);
constant float resY = float($height) / float($gameHeight);
#define fxaa $fxaa

#define SET_POSITION(_v)                                                       \
    out.position = _v;                                                         \
    out.position.z = (out.position.z + out.position.w) / 2.0
// start of shader inputs/outputs, predetermined by Cemu. Do not touch
struct SupportBuffer {
    int4 remapped[4];
    float2 fragCoordScale;
};

#define GET_FRAGCOORD()                                                        \
    float4(in.position.xy *supportBuffer.fragCoordScale.xy, in.position.z,     \
           1.0 / in.position.w)
struct FragmentIn {
    float4 position [[position]];
    float4 passParameterSem2 [[user(locn0)]];
};

struct FragmentOut {
    float4 passPixelColor0 [[color(0)]];
};

// end of shader inputs/outputs
template <typename TextureT, typename CoordT>
float sampleCompareEmulate(TextureT tex, sampler samplr, CoordT coord,
                           float compareValue) {
    return compareValue < tex.sample(samplr, coord).x ? 1.0 : 0.0;
}
template <typename TextureT, typename CoordT>
float2 textureCalculateLod(TextureT tex, sampler samplr, CoordT coord) {
    float lod = tex.calculate_unclamped_lod(samplr, coord);
    return float2(floor(lod), fract(lod));
}
int clampFI32(int v) {
    if (v == 0x7FFFFFFF)
        return as_type<int>(1.0);
    else if (v == 0xFFFFFFFF)
        return as_type<int>(0.0);
    return as_type<int>(clamp(as_type<float>(v), 0.0, 1.0));
}
float mul_nonIEEE(float a, float b) {
    if (a == 0.0 || b == 0.0)
        return 0.0;
    return a * b;
}
fragment FragmentOut main0(FragmentIn in [[stage_in]],
                           float2 pointCoord [[point_coord]],
                           bool frontFacing [[front_facing]],
                           constant SupportBuffer &supportBuffer [[buffer(0)]],
                           texture2d<float> tex0 [[texture(0)]],
                           sampler samplr0 [[sampler(0)]],
                           texture2d<float> tex1 [[texture(1)]],
                           sampler samplr1 [[sampler(1)]]) {
    FragmentOut out;
#if fxaa == 0
    out.passPixelColor0 = tex0.sample(samplr0, in.passParameterSem2.xy);
#else
    float4 R0f = float4(0.0);
    float4 R1f = float4(0.0);
    float4 R2f = float4(0.0);
    float4 R3f = float4(0.0);
    float4 R123f = float4(0.0);
    float4 R126f = float4(0.0);
    float4 R127f = float4(0.0);
    float backupReg0f, backupReg1f, backupReg2f, backupReg3f, backupReg4f;
    float PV0fx = 0.0, PV0fy = 0.0, PV0fz = 0.0, PV0fw = 0.0, PV1fx = 0.0,
          PV1fy = 0.0, PV1fz = 0.0, PV1fw = 0.0;
    float PS0f = 0.0, PS1f = 0.0;
    float4 tempf = float4(0.0);
    float tempResultf;
    int tempResulti;
    int4 ARi = int4(0);
    bool predResult = true;
    bool activeMaskStack[2];
    bool activeMaskStackC[3];
    activeMaskStack[0] = false;
    activeMaskStackC[0] = false;
    activeMaskStackC[1] = false;
    activeMaskStack[0] = true;
    activeMaskStackC[0] = true;
    activeMaskStackC[1] = true;
    R0f = in.passParameterSem2;
    if (activeMaskStackC[1] == true) {
        R1f.xyzw =
            (tex1.gather(samplr1, float2(0.0001) + float2(R0f.x, R0f.y)).wzxy);
        R2f.xyzw = (tex0.sample(samplr0, float2(R0f.x, R0f.y)).xyzw);
    }
    if (activeMaskStackC[1] == true) {
        activeMaskStack[1] = activeMaskStack[0];
        activeMaskStackC[2] = activeMaskStackC[1];
        // 0
        PV0fx = R1f.w + -(R1f.x);
        PV0fy = R1f.z + -(R1f.y);
        PV0fz = mul_nonIEEE(R2f.x, as_type<float>(supportBuffer.remapped[0].x));
        R127f.w = min(R1f.z, R1f.x);
        R127f.x = min(R1f.w, R1f.y);
        // 1
        R123f.x =
            mul_nonIEEE(R2f.y,
                        as_type<float>(supportBuffer.remapped[0].y) * resX) +
            PV0fz;
        PV1fy = max(R1f.z, R1f.x);
        R127f.z = PV0fy + -(PV0fx);
        R126f.w = PV0fy + PV0fx;
        PS1f = max(R1f.w, R1f.y);
        // 2
        PV0fx = max(R127f.z, -(R127f.z));
        PV0fy = max(R126f.w, -(R126f.w));
        R123f.z =
            mul_nonIEEE(R2f.z, as_type<float>(supportBuffer.remapped[0].z)) +
            R123f.x;
        PV0fw = min(R127f.w, R127f.x);
        PS0f = max(PV1fy, PS1f);
        // 3
        PV1fx = mul_nonIEEE(PS0f, as_type<float>(supportBuffer.remapped[1].x));
        PV1fy = max(R123f.z, PS0f);
        PV1fz = min(R123f.z, PV0fw);
        PV1fw = min(PV0fy, PV0fx);
        // 4
        R1f.x = -(PV1fz) + PV1fy;
        R0f.z = max(PV1fx, as_type<float>(supportBuffer.remapped[1].y));
        PS0f = 1.0 / PV1fw;
        // 5
        PV1fx = mul_nonIEEE(R127f.z, PS0f);
        PV1fy = mul_nonIEEE(R126f.w, PS0f);
        // 6
        PV0fz = max(PV1fx, -(as_type<float>(supportBuffer.remapped[2].y)));
        PV0fw = max(PV1fy, -(as_type<float>(supportBuffer.remapped[2].y)));
        // 7
        R3f.x = min(PV0fw, as_type<float>(supportBuffer.remapped[2].y));
        R1f.y = min(PV0fz, as_type<float>(supportBuffer.remapped[2].y));
        // 8
        predResult = (R1f.x > R0f.z);
        activeMaskStack[1] = predResult;
        activeMaskStackC[2] = predResult == true && activeMaskStackC[1] == true;
    } else {
        activeMaskStack[1] = false;
        activeMaskStackC[2] = false;
    }
    if (activeMaskStackC[2] == true) {
        // 0
        backupReg0f = R3f.x;
        R3f.x =
            mul_nonIEEE(backupReg0f,
                        as_type<float>(supportBuffer.remapped[3].x) / resX) +
            R0f.x;
        R3f.y = mul_nonIEEE(R1f.y, as_type<float>(supportBuffer.remapped[3].y) /
                                       resY) +
                R0f.y;
        R1f.x =
            mul_nonIEEE(backupReg0f,
                        -(as_type<float>(supportBuffer.remapped[3].x) / resX)) +
            R0f.x;
        // 1
        R1f.y =
            mul_nonIEEE(R1f.y,
                        -(as_type<float>(supportBuffer.remapped[3].y) / resY)) +
            R0f.y;
    }
    if (activeMaskStackC[2] == true) {
        R0f.xyzw = (tex0.sample(samplr0, float2(R3f.x, R3f.y)).xyzw);
        R1f.xyzw = (tex0.sample(samplr0, float2(R1f.x, R1f.y)).xyzw);
    }
    if (activeMaskStackC[2] == true) {
        // 0
        R127f.x = R0f.w + R1f.w;
        R127f.x /= 2.0;
        R127f.y = R0f.z + R1f.z;
        R127f.y /= 2.0;
        R127f.z = R0f.y + R1f.y;
        R127f.z /= 2.0;
        R127f.w = R0f.x + R1f.x;
        R127f.w /= 2.0;
        // 1
        PV1fx = R2f.w + -(R127f.x);
        PV1fy = R2f.z + -(R127f.y);
        PV1fz = R2f.y + -(R127f.z);
        PV1fw = R2f.x + -(R127f.w);
        // 2
        R2f.x = PV1fw * as_type<float>(0x3eb33333) + R127f.w;
        R2f.y = PV1fz * as_type<float>(0x3eb33333) + R127f.z;
        R2f.z = PV1fy * as_type<float>(0x3eb33333) + R127f.y;
        R2f.w = PV1fx * as_type<float>(0x3eb33333) + R127f.x;
    }
    activeMaskStackC[1] =
        activeMaskStack[0] == true && activeMaskStackC[0] == true;
    // export
    out.passPixelColor0 = as_type<float4>(float4(R2f.x, R2f.y, R2f.z, R2f.w));
#endif
    return out;
}
