#shader CRandomStaticFilterAlpha
#attribute position4
#attribute uv4
#srcfac srcalpha
#dstfac invsrcalpha
#primitive tristrips
#depthtest none
#depthwrite false
#culling none

#vertex glsl
layout(location=0) in vec4 posIn;
layout(location=1) in vec4 uvIn;

UBINDING0 uniform RandomStaticUniform
{
    vec4 color;
    float randOff;
    float discardThres;
};

struct VertToFrag
{
    vec4 color;
    vec2 uv;
    float randOff;
    float discardThres;
};

SBINDING(0) out VertToFrag vtf;
void main()
{
    vtf.color = color;
    vtf.uv = uvIn.xy;
    vtf.randOff = randOff;
    vtf.discardThres = discardThres;
    gl_Position = vec4(posIn.xyz, 1.0);
}

#fragment glsl
struct VertToFrag
{
    vec4 color;
    vec2 uv;
    float randOff;
    float discardThres;
};

ivec2 Lookup8BPP(in vec2 uv, in float randOff)
{
    int bx = int(uv.x) >> 3;
    int rx = int(uv.x) & 0x7;
    int by = int(uv.y) >> 2;
    int ry = int(uv.y) & 0x3;
    int bidx = by * 128 + bx;
    int addr = bidx * 32 + ry * 8 + rx + int(randOff);
    return ivec2(addr & 0x3ff, addr >> 10);
}

SBINDING(0) in VertToFrag vtf;
layout(location=0) out vec4 colorOut;
TBINDING0 uniform sampler2D tex;
void main()
{
    colorOut = texelFetch(tex, Lookup8BPP(vtf.uv, vtf.randOff), 0) * vtf.color;
    colorOut.a = vtf.color.a;
}

#vertex hlsl
struct VertData
{
    float4 posIn : POSITION;
    float2 uvIn : UV;
};

cbuffer RandomStaticUniform : register(b0)
{
    float4 color;
    float randOff;
   float discardThres;
};

struct VertToFrag
{
    float4 pos : SV_Position;
    float4 color : COLOR;
    float2 uv : UV;
    float randOff : RANDOFF;
    float discardThres : DISCARDTHRES;
};

VertToFrag main(in VertData v)
{
    VertToFrag vtf;
    vtf.color = color;
    vtf.uv = v.uvIn.xy;
    vtf.randOff = randOff;
    vtf.discardThres = discardThres;
    vtf.pos = float4(v.posIn.xyz, 1.0);
    return vtf;
}

#fragment hlsl
struct VertToFrag
{
    float4 pos : SV_Position;
    float4 color : COLOR;
    float2 uv : UV;
    float randOff : RANDOFF;
    float discardThres : DISCARDTHRES;
};

static int3 Lookup8BPP(float2 uv, float randOff)
{
    int bx = int(uv.x) >> 3;
    int rx = int(uv.x) & 0x7;
    int by = int(uv.y) >> 2;
    int ry = int(uv.y) & 0x3;
    int bidx = by * 128 + bx;
    int addr = bidx * 32 + ry * 8 + rx + int(randOff);
    return int3(addr & 0x3ff, addr >> 10, 0);
}

Texture2D tex : register(t0);
float4 main(in VertToFrag vtf) : SV_Target0
{
    float4 colorOut = tex.Load(Lookup8BPP(vtf.uv, vtf.randOff)) * vtf.color;
    colorOut.a = vtf.color.a;
    return colorOut;
}

#vertex metal
struct VertData
{
    float4 posIn [[ attribute(0) ]];
    float2 uvIn [[ attribute(1) ]];
};

struct RandomStaticUniform
{
    float4 color;
    float randOff;
    float discardThres;
};

struct VertToFrag
{
    float4 pos [[ position ]];
    float4 color;
    float2 uv;
    float randOff;
    float discardThres;
};

vertex VertToFrag vmain(VertData v [[ stage_in ]],
                        constant RandomStaticUniform& su [[ buffer(2) ]])
{
    VertToFrag vtf;
    vtf.color = su.color;
    vtf.uv = v.uvIn.xy;
    vtf.randOff = su.randOff;
    vtf.discardThres = su.discardThres;
    vtf.pos = float4(v.posIn.xyz, 1.0);
    return vtf;
}

#fragment metal
struct VertToFrag
{
    float4 pos [[ position ]];
    float4 color;
    float2 uv;
    float randOff;
    float discardThres;
};

static uint2 Lookup8BPP(float2 uv, float randOff)
{
    int bx = int(uv.x) >> 3;
    int rx = int(uv.x) & 0x7;
    int by = int(uv.y) >> 2;
    int ry = int(uv.y) & 0x3;
    int bidx = by * 128 + bx;
    int addr = bidx * 32 + ry * 8 + rx + int(randOff);
    return uint2(addr & 0x3ff, addr >> 10);
}

fragment float4 fmain(VertToFrag vtf [[ stage_in ]],
                      texture2d<float> tex [[ texture(0) ]])
{
    float4 colorOut = tex.read(Lookup8BPP(vtf.uv, vtf.randOff)) * vtf.color;
    colorOut.a = vtf.color.a;
    return colorOut;
}

#shader CRandomStaticFilterAdd : CRandomStaticFilterAlpha
#srcfac srcalpha
#dstfac one

#shader CRandomStaticFilterMult : CRandomStaticFilterAlpha
#srcfac zero
#dstfac srccolor
#overwritealpha true

#shader CRandomStaticFilterCookieCutter : CRandomStaticFilterAlpha
#srcfac zero
#dstfac srccolor
#overwritealpha true
#depthwrite true
#colorwrite false
#depthtest lequal

#fragment glsl
struct VertToFrag
{
    vec4 color;
    vec2 uv;
    float randOff;
    float discardThres;
};

ivec2 Lookup8BPP(in vec2 uv, in float randOff)
{
    int bx = int(uv.x) >> 3;
    int rx = int(uv.x) & 0x7;
    int by = int(uv.y) >> 2;
    int ry = int(uv.y) & 0x3;
    int bidx = by * 128 + bx;
    int addr = bidx * 32 + ry * 8 + rx + int(randOff);
    return ivec2(addr & 0x3ff, addr >> 10);
}

SBINDING(0) in VertToFrag vtf;
layout(location=0) out vec4 colorOut;
TBINDING0 uniform sampler2D tex;
void main()
{
    colorOut = texelFetch(tex, Lookup8BPP(vtf.uv, vtf.randOff), 0) * vtf.color;
    if (colorOut.a < vtf.discardThres)
        discard;
}

#fragment hlsl
struct VertToFrag
{
    float4 pos : SV_Position;
    float4 color : COLOR;
    float2 uv : UV;
    float randOff : RANDOFF;
    float discardThres : DISCARDTHRES;
};

static int3 Lookup8BPP(float2 uv, float randOff)
{
    int bx = int(uv.x) >> 3;
    int rx = int(uv.x) & 0x7;
    int by = int(uv.y) >> 2;
    int ry = int(uv.y) & 0x3;
    int bidx = by * 128 + bx;
    int addr = bidx * 32 + ry * 8 + rx + int(randOff);
    return int3(addr & 0x3ff, addr >> 10, 0);
}

Texture2D tex : register(t0);
float4 main(in VertToFrag vtf) : SV_Target0
{
    float4 colorOut = tex.Load(Lookup8BPP(vtf.uv, vtf.randOff)) * vtf.color;
    if (colorOut.a < vtf.discardThres)
        discard;
    return colorOut;
}

#fragment metal
struct VertToFrag
{
    float4 pos [[ position ]];
    float4 color;
    float2 uv;
    float randOff;
    float discardThres;
};

static uint2 Lookup8BPP(float2 uv, float randOff)
{
    int bx = int(uv.x) >> 3;
    int rx = int(uv.x) & 0x7;
    int by = int(uv.y) >> 2;
    int ry = int(uv.y) & 0x3;
    int bidx = by * 128 + bx;
    int addr = bidx * 32 + ry * 8 + rx + int(randOff);
    return uint2(addr & 0x3ff, addr >> 10);
}

fragment float4 fmain(VertToFrag vtf [[ stage_in ]],
                      texture2d<float> tex [[ texture(0) ]])
{
    float4 colorOut = tex.read(Lookup8BPP(vtf.uv, vtf.randOff)) * vtf.color;
    if (colorOut.a < vtf.discardThres)
        discard_fragment();
    return colorOut;
}
