{
  "name": "Bling",
  "type": "static",
  "passes": [
    {
      "name": "bling",
      "inputs": [
        "default"
      ],
      "glsl": "precision highp float;

varying vec2 textureCoordinate;
varying vec2 sourceTextureCoordinate;

// default uniforms for all filters
uniform float time_sec;
uniform float strength;
uniform vec2 outputSize; // size of the output fbo
uniform vec2 inputSize; // size of the original default input texture
uniform vec2 tex0Size; // size of tex0 for this pass

// default uniforms for transitions and video effects
uniform float progress; // normalized 0-1

// default uniforms for video effects
uniform float duration; // in seconds
uniform float clipDuration; // in seconds

uniform float lowThreshold;
uniform float highThreshold;
uniform float radius;
uniform float r;
uniform float g;
uniform float b;

#define GRID_X 18
#define GRID_Y 24


// effect uniforms
void main() {

  vec2 uv = sourceTextureCoordinate;
  vec4 base = sampleInput(uv);

  vec2 asp = vec2(outputSize.x / outputSize.y, 1.0) * 4.0;
  float ang = 0.78539816339;
  float ca = cos(ang);
  float sa = sin(ang);
  mat2 rot2d = mat2(ca, -sa, sa, ca);

  vec3 sparkleAccum = vec3(0.0);

  for (int ix = 0; ix < GRID_X; ix++){

    float fx = (float(ix) + 0.5) / float(GRID_X);

    for (int iy = 0; iy < GRID_Y; iy++){
      vec2 cellUV = vec2(fx, (float(iy) + 0.5) / float(GRID_Y));

      float lum = dot(sampleInput(cellUV).rgb, vec3(0.299,0.587,0.114));

      float str = smoothstep(lowThreshold, highThreshold, lum) * (1.0 - step(highThreshold, lum));
      if (str <= 0.2) continue;

      vec2 p0 = (uv - cellUV) * asp;
      vec2 p = rot2d * p0;
      float falloff = sqrt(abs(p.x)) + sqrt(abs(p.y));
      float denom = max(10.0, radius * falloff + 2.0);
      float br = 250.0 * pow(1.0/denom, 2.5);

      vec3 star = mix(vec3(r * br, g * br, b * br), vec3(1.0), br) * str;
      sparkleAccum += star;
    }
  }

  vec3 color = base.rgb + sparkleAccum;
  gl_FragColor = toOutputFormat(vec4(color,1.0));
}
",
      "metal": "using namespace metal;
struct fragmentIn { float2 textureCoordinate [[user(locn0)]]; float2 sourceTextureCoordinate [[user(locn1)]]; };
struct fragmentOut { float4 _gl_FragColor [[color(0)]]; };
typedef struct {
  float4x4 content_transform;
  float4x4 texture_transform;
  float strength;
  float progress;
  float time_sec;
  float duration_sec;
  float clip_duration_sec;
  float2 input_size;
  float2 output_size;
  float2 tex0Size;
  float lowThreshold;
  float highThreshold;
  float radius;
  float r;
  float g;
  float b;
 } Uniforms;
#define GRID_X 18
#define GRID_Y 24


// effect uniforms
fragment fragmentOut fragmentShader(fragmentIn in [[stage_in]],
 constant Uniforms & uniforms [[buffer(1)]],
 DefaultInputs defaultInputs) {

  float2 uv = in.sourceTextureCoordinate;
  float4 base = sampleInput(defaultInputs, uv);

  float2 asp = float2(uniforms.output_size.x / uniforms.output_size.y, 1.0) * 4.0;
  float ang = 0.78539816339;
  float ca = cos(ang);
  float sa = sin(ang);
  float2x2 rot2d = float2x2(ca, -sa, sa, ca);

  float3 sparkleAccum = float3(0.0);

  for (int ix = 0; ix < GRID_X; ix++){

    float fx = (float(ix) + 0.5) / float(GRID_X);

    for (int iy = 0; iy < GRID_Y; iy++){
      float2 cellUV = float2(fx, (float(iy) + 0.5) / float(GRID_Y));

      float lum = dot(sampleInput(defaultInputs, cellUV).rgb, float3(0.299,0.587,0.114));

      float str = smoothstep(uniforms.lowThreshold, uniforms.highThreshold, lum) * (1.0 - step(uniforms.highThreshold, lum));
      if (str <= 0.2) continue;

      float2 p0 = (uv - cellUV) * asp;
      float2 p = rot2d * p0;
      float falloff = sqrt(abs(p.x)) + sqrt(abs(p.y));
      float denom = max(10.0, uniforms.radius * falloff + 2.0);
      float br = 250.0 * pow(1.0/denom, 2.5);

      float3 star = mix(float3(uniforms.r * br, uniforms.g * br, uniforms.b * br), float3(1.0), br) * str;
      sparkleAccum += star;
    }
  }

  float3 color = base.rgb + sparkleAccum;
  return {toOutputFormat(float4(color,1.0))};
}",
      "uniforms": {
        "lowThreshold": {
          "value": 0.8
        },
        "highThreshold": {
          "value": 0.85
        },
        "radius": {
          "value": 35.0
        },
        "r": {
          "value": 1.0
        },
        "g": {
          "value": 0.5
        },
        "b": {
          "value": 0.0
        }
      }
    }
  ]
}
