{
  "name": "Infinite Grid",
  "curve": "Quadratic InOut",
  "duration": 3,
  "type": "fixed-intro",
  "passes": [
    {
      "name": "infinite grid",
      "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 depth;
uniform float shiftCenterX;
uniform float shiftCenterY;

uniform float pitchVal;
uniform float scaleVal;


float catmullRom(float a, float b, float c, float d, float t){
  float t2 = t*t;
  float t3 = t2 * t;
  return 0.5 * ((2.0 * b) + (-a + c) * t + (2.0 * a - 5.0 * b + 4.0 * c - d) * t2 + (-a + 3.0 * b - 3.0 * c + d) * t3);
}



// effect uniforms
void main() {
  vec2 uv = sourceTextureCoordinate;

  // revert in GL shader
  float pitchValGl = -pitchVal;
  float shiftCenterYGl = -shiftCenterY;

  float p = clamp(progress, 0.0, 1.0);
  p = 1.0 - p;
  vec2 scale = vec2(max(scaleVal, 0.001));

  float pitch = radians(pitchValGl *  p);

  vec2 ndc = uv * 2.0 - 1.0;
  vec3 ray = normalize(vec3(ndc, 1.0));

  float cx = cos(pitch);
  float sx = sin(pitch);

  mat3 Rx = mat3(1.0, 0.0, 0.0, 0.0, cx, -sx, 0.0, sx, cx);
  mat3 R = Rx;

  vec3 origin = vec3(0.0,0.0,0.0);
  vec3 camera = vec3(shiftCenterX,(shiftCenterYGl * p),((depth * p) + 1.0));
  vec3 originNew = R * (origin - camera) + camera;
  vec3 newRay = R * ray;
  float t = (((depth * p) + 1.0) - originNew.z) / max(newRay.z, 1e-4);
  vec3 hit = originNew + newRay * t;
  vec3 axisX = R * vec3(1.0,0.0,0.0);
  vec3 axisY = R * vec3(0.0,1.0,0.0);
  vec2 plane = vec2(dot(hit - camera, axisX), dot(hit - camera, axisY));

  scale.x = scale.y * (max(scaleVal, 0.001));
  uv = plane * 0.5 + 0.5;
  uv = (uv - 0.5) / scale + 0.5;

  uv = fract(uv);

  vec4 base =  sampleInput(uv);
  vec4 color = vec4(base);
  gl_FragColor = toOutputFormat(color);
}
",
      "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 depth;
  float shiftCenterX;
  float shiftCenterY;
  float pitchVal;
  float scaleVal;
 } Uniforms;
float catmullRom(float a, float b, float c, float d, float t){
  float t2 = t*t;
  float t3 = t2 * t;
  return 0.5 * ((2.0 * b) + (-a + c) * t + (2.0 * a - 5.0 * b + 4.0 * c - d) * t2 + (-a + 3.0 * b - 3.0 * c + d) * t3);
}



// effect uniforms
fragment fragmentOut fragmentShader(fragmentIn in [[stage_in]],
 constant Uniforms & uniforms [[buffer(1)]],
 DefaultInputs defaultInputs) {
  float2 uv = in.sourceTextureCoordinate;


  float p = clamp(uniforms.progress, 0.0, 1.0);
  p = 1.0 - p;
  float2 scale = float2(max(uniforms.scaleVal, 0.001));

  float pitch = (uniforms.pitchVal *  p * M_PI_F / 180.0);

  float2 ndc = uv * 2.0 - 1.0;
  float3 ray = normalize(float3(ndc, 1.0));

  float cx = cos(pitch);
  float sx = sin(pitch);

  float3x3 Rx = float3x3(1.0, 0.0, 0.0, 0.0, cx, -sx, 0.0, sx, cx);
  float3x3 R = Rx;

  float3 origin = float3(0.0,0.0,0.0);
  float3 camera = float3(uniforms.shiftCenterX,(uniforms.shiftCenterY * p),((uniforms.depth * p) + 1.0));
  float3 originNew = R * (origin - camera) + camera;
  float3 newRay = R * ray;
  float t = (((uniforms.depth * p) + 1.0) - originNew.z) / max(newRay.z, 1e-4);
  float3 hit = originNew + newRay * t;
  float3 axisX = R * float3(1.0,0.0,0.0);
  float3 axisY = R * float3(0.0,1.0,0.0);
  float2 plane = float2(dot(hit - camera, axisX), dot(hit - camera, axisY));

  scale.x = scale.y * (max(uniforms.scaleVal, 0.001));
  uv = plane * 0.5 + 0.5;
  uv = (uv - 0.5) / scale + 0.5;

  uv = fract(uv);

  float4 base =  sampleInput(defaultInputs, uv);
  float4 color = float4(base);
  return {toOutputFormat(color)};
}
",
      "uniforms": {
        "pitchVal": {
          "value": -42
        },
        "scaleVal": {
          "value": 1.0
        },
        "shiftCenterX": {
          "value": 0.0
        },
        "shiftCenterY": {
          "value": -0.5
        },
        "depth": {
          "value": 2.5
        }
      }
    }
  ]
}
