//var gl = new WebGL2RenderingContext(); //enable WebGL 2 partial support

Demo.prototype.init = function () {
  const settings = new Settings();
  settings.demo.sync.rocketFile = 'demo.rocket';
  settings.demo.sync.beatsPerMinute = 115;
  settings.demo.sync.rowsPerBeat = 8;
  var start = 0;
  var duration = 60;
  var layer = 1;
  var scaleFactor = 1.0;




  this.loader.addAnimation(
    {
      "start": 0, "duration": duration, "layer": layer
      , "image": "_embedded/defaultWhite.png",
      color: [
        {
          r: 2,
          g: 0,
          b: 0
        }
      ],
    });

  this.loader.addAnimation(
    {
      "start": 0, "duration": duration, "layer": layer
      , "image": "_embedded/defaultWhite.png",
      scale: [{ uniform3d: () => (getSceneTimeFromStart() % 0.288) * 0.3 + 0.6 }],
      color: [
        {
          r: 0,
          g: 0,
          b: 0
        }
      ],
    });

  this.loader.addAnimation(
    {
      "start": 0, "duration": duration, "layer": layer
      , "image": "_embedded/defaultWhite.png",
      scale: [{ uniform3d: 0.2 }],
      color: [
        {
          r: 2,
          g: 0,
          b: 0
        }
      ],
      position: [
        {
          x: () => 0,
          y: () => 0,
          z: () => 0
        }
      ]
    });
  this.loader.addAnimation(
    {
      "start": 0, "duration": duration, "layer": layer
      , "image": "_embedded/defaultWhite.png",
      scale: [{ uniform3d: 0.2 }],
      color: [
        {
          r: 2,
          g: 0,
          b: 0
        }
      ],
      position: [
        {
          x: () => 0,
          y: () => 0,
          z: () => 0
        }
      ]
    });

  for (let i = 0; i < 2; i++) {
    this.loader.addAnimation(
      {
        "start": 0, "duration": duration, "layer": layer
        , "image": "_embedded/defaultWhite.png",
        scale: [{ uniform3d: 0.2 }],
        color: [
          {
            r: 2,
            g: 0,
            b: 0,
            a: () => Math.sin(getSceneTimeFromStart() * 4 + i)
          }
        ],
        position: [
          {
            x: () => 0.4 - (0.8 * i),
            y: () => 0.4,
            z: () => 0
          }
        ]
      });
  }
  for (let i = 0; i < 2; i++) {
    this.loader.addAnimation(
      {
        "start": 0, "duration": duration, "layer": layer
        , "image": "_embedded/defaultWhite.png",
        scale: [{ uniform3d: 0.2 }],
        color: [
          {
            r: 0,
            g: 0,
            b: 0,
            a: () => Math.sin(getSceneTimeFromStart() * 5 + i)
          }
        ],
        position: [
          {
            x: () => 0.4 - (0.8 * i),
            y: () => -0.4,
            z: () => 0
          }
        ]
      });
  }


  this.loader.addAnimation({
    start: start,
    duration: duration,
    layer: 500,
    light: {
      type: 'Directional',
      // animate intensity
      properties: { intensity: () => 13 }
    },
    color: [{ r: 1.0, g: 1.0, b: 1.0 }],
    position: [
      {
        x: () => 0,
        y: () => 2,
        z: () => 1
      }
    ]
  });

  this.loader.addAnimation([
    {
      start: start,
      duration: 100,

      scale: [{ uniform3d: 1.5 * scaleFactor }],
      object: { name: 'stage.obj' },
      position: [
        {
          x: () => 0,
          y: () => 0,
          z: () => 0.
        }
      ],
      color: [
        {
          r: () => 1,
          g: () => 1,
          b: () => 1
        }
      ],
      angle: [
        {
          degreesY: () => 0,
          degreesX: () => 0,
          degreesZ: () => 0
        }
      ]
    }
  ]);


  this.loader.addAnimation([
    {
      start: start,
      duration: 100,

      scale: [{ uniform3d: 1 * scaleFactor }],
      object: { name: 'tsikengore.obj' },
      position: [
        {
          x: () => 0,
          y: () => -4 * scaleFactor,
          z: () => 0.
        }
      ],
      color: [
        {
          r: () => 1,
          g: () => 1,
          b: () => 1
        }
      ],
      angle: [
        {
          degreesY: () => 0,
          degreesX: () => 0,
          degreesZ: () => 0
        }
      ]
    }
  ]);


  const deg2rad = 0.0174533;

  this.loader.addAnimation({
    "camera": "cam1"
    , "position": [{ "x": 0, "y": 0, "z": 10 }]
    , "lookAt": [{ "x": 0.0, "y": 0.0, "z": 0.0 }]
    , "up": [{ "x": 0, "y": 1, "z": 0 }]
    , "perspective": [{ "fov": 75, "aspect": 16 / 9, "near": .05, "far": 1000 }]
    , "distYawPitch": [-5.0, 1, 2.0]
    , "instableTimer": [0.0, 0.0, 0.0, 0.0, 0.0]
    , "runPreFunction": (animation) => {
      for (let i = 0; i < animation.instableTimer.length; i++) {
        animation.instableTimer[i] += Math.random() * getDeltaTime();
      }
      let distance = .05 * Sync.get('Cam:Instability') * Math.sin(1.8 * animation.instableTimer[3]) + Sync.get('Cam:Distance');
      let pitch = (Sync.get('Cam:Instability') * 5 * Math.cos(2.4 * animation.instableTimer[1]) + Sync.get('Cam:Yaw')) * deg2rad;
      let roll = (Sync.get('Cam:Instability') * 5 * Math.sin(3.1 * animation.instableTimer[2]) + Sync.get('Cam:Pitch')) * deg2rad;
      let yaw = 0.0;
      let target = [Sync.get('Cam:TargetX') * scaleFactor, Sync.get('Cam:TargetY') * scaleFactor, Sync.get('Cam:TargetZ') * scaleFactor];
      let points = [0, 0, distance];
      let cosa = Math.cos(yaw),
        sina = Math.sin(yaw);
      let cosb = Math.cos(pitch),
        sinb = Math.sin(pitch);
      let cosc = Math.cos(roll),
        sinc = Math.sin(roll);
      let Axx = cosa * cosb,
        Axy = cosa * sinb * sinc - sina * cosc,
        Axz = cosa * sinb * cosc + sina * sinc;
      let Ayx = sina * cosb,
        Ayy = sina * sinb * sinc + cosa * cosc,
        Ayz = sina * sinb * cosc - cosa * sinc;
      let Azx = -sinb,
        Azy = cosb * sinc,
        Azz = cosb * cosc;
      let px = points[0];
      let py = points[1];
      let pz = points[2];
      let newPoints = [
        (Axx * px + Axy * py + Axz * pz) + target[0],
        Ayx * px + Ayy * py + Ayz * pz + target[1],
        Azx * px + Azy * py + Azz * pz + target[2]
      ];
      window.camPos = newPoints;
      window.camPosLength = Math.sqrt(newPoints[0] * newPoints[0] + newPoints[1] * newPoints[1] + newPoints[2] * newPoints[2]);
      animation.position[0].x = newPoints[0];
      animation.position[0].y = newPoints[1];
      animation.position[0].z = newPoints[2];
      animation.lookAt[0].x = Sync.get('Cam:Instability') * .25 * Math.sin(2 * animation.instableTimer[3]) + Sync.get('Cam:TargetX');
      animation.lookAt[0].y = Sync.get('Cam:Instability') * .25 * Math.cos(2 * animation.instableTimer[4]) + Sync.get('Cam:TargetY');
      animation.lookAt[0].z = Sync.get('Cam:TargetZ');
      animation.perspective[0].fov = Sync.get('Cam:FOV');
      window.camNear = animation.perspective[0].near;
      window.camFar = animation.perspective[0].far;
      window.camFov = animation.perspective[0].fov * deg2rad;

      let camRoll = Sync.get('Cam:Roll') * deg2rad;
      animation.up[0].x = -Math.sin(camRoll);
      animation.up[0].y = Math.cos(camRoll);
      animation.up[0].z = 0;

    }
  });




  for (let i = 0; i < 1; i++) {
    let farmerDead = false;
    let exploStartTime = 0;
    this.addExplosion(
      () => {
        console.log(Sync.get('Farmer' + i + ':State'));
        if (Sync.get('Farmer' + i + ':State') === 4) {
          if (!farmerDead) {
            farmerDead = true;
            exploStartTime = getSceneTimeFromStart();
          }
          return getSceneTimeFromStart() - exploStartTime;
        }
        farmerDead = false;
        exploStartTime = 0;
        return 0;
      },
      "bokfsd.png",
      null,                   // model
      0.1, 3,  // startTime, duration
      6, 33, 4,  // maxDist, amount, scale
      () => Sync.get('Farmer' + i + ':X'), () => Sync.get('Farmer' + i + ':Y'), () => Sync.get('Farmer' + i + ':Z'),        // posX, posY, posZ
      .1, 1, .1,        // startDim
      2, .25, 2,   // dimX, dimY, dimZ
      0, 0, 0,        // xOffset, yOffset, zOffset
      "NormalBlending", // blendmode
      null);

    this.loader.addAnimation([{
      object: {
        name: "farmer.obj",
      },
      visible: () => Sync.get('Farmer' + i + ':State') < 4,
      billboard: true,
      position: [{
        x: () => Sync.get('Farmer' + i + ':X') * scaleFactor,
        y: () => Sync.get('Farmer' + i + ':Y') * scaleFactor,
        z: () => Sync.get('Farmer' + i + ':Z') * scaleFactor,
      }],
      angle: [{
        degreesZ: () => getSceneTimeFromStart() * 45,
      }],
      scale: [{ uniform3d: .5 }],
      shader: {
        name: 'farmer.fs',
        variable: [
          { name: 'farmerState', value: [() => Sync.get('Farmer' + i + ':State')] },
          { name: 'farmerInterval', value: [0.2] },
          { name: 'alphaThreshold', value: [0.1] },
          { name: 'farmerTime', value: [() => getSceneTimeFromStart()] }
        ]
      }
    }]);
  }

  this.loader.addAnimation(
    {
      "start": 0, "duration": 555, "layer": layer
      , "image": "beak.png",
      perspective: "2d",
      material: {
        blending: "NormalBlending",
        transparent: true,
        depthWrite: false,
        depthTest: false
      },
      scale: [{ x: 1.7, y: 2.1 }],
      position: [
        {
          y: () => Sync.get('Overlay:BeakPosition'),
        }
      ],
    });

      this.loader.addAnimation(
    {
      "start": 0, "duration": duration, "layer": layer
      , "image": "youdie.png",
      perspective: "2d",
      material: {
        blending: "NormalBlending",
        transparent: true,
        depthWrite: false,
        depthTest: false
      },
      position: [
        {
          y: .5,
        }
      ],
      color: [
        {
          a: () => Sync.get('Overlay:DamageAlpha'),
          r: () => Sync.get('Overlay:DamageRed'),
        }
      ],
      scale: [{ uniform2d: 13.8 }],
    });

  this.loader.addAnimation(
    {
      "start": 0, "duration": duration, "layer": layer
      , "image": "youdie.png",
      perspective: "2d",
      material: {
        blending: "NormalBlending",
        transparent: true,
        depthWrite: false,
        depthTest: false
      },
      position: [
        {
          y: () => Sync.get('Overlay:DiePosition'),
        }
      ],
      scale: [{ uniform2d: 3.8 }],
    });


  this.loader.addAnimation(
    {
      "start": 0, "duration": 555, "layer": layer
      , "image": "lore.png",
      perspective: "2d",
      material: {
        blending: "NormalBlending",
        transparent: true,
        depthWrite: false,
        depthTest: false
      },
      position: [
        {
          y: () => Sync.get('Overlay:LorePosition'),
        }
      ],
    });


}




Demo.prototype.addExplosion = function (timeFunction, particleTexture, particleModel, startTime, duration, maxDist, amount, particleScale, posX, posY, posZ, xStartDim, yStartDim, zStartDim, xDim = 0.1, yDim = 0.1, zDim = 0.0, xOffset, yOffset, zOffset, blendingMode = "CustomBlending", parentId = "scene") {

  let particles = new Array(amount);
  for (let i = 0; i < particles.length; i++) {

    let xStart = Math.random() * xStartDim - xStartDim * .5;
    let yStart = Math.random() * yStartDim - yStartDim * .5;
    let zStart = Math.random() * zStartDim - zStartDim * .5;
    let xStartDir = (xStart != 0) ? xStart / Math.abs(xStart) : 0;
    let yStartDir = (yStart != 0) ? yStart / Math.abs(yStart) : 0;
    let zStartDir = (zStart != 0) ? zStart / Math.abs(zStart) : 0;
    let xDir = Math.random() * (xDim + xStartDir);
    let yDir = Math.random() * (yDim + yStartDir);
    let zDir = Math.random() * (zDim + zStartDir);
    xStart += 0;
    yStart += 0;
    zStart += 0;

    let vectorLength = Math.sqrt(xDir * xDir + yDir * yDir + zDir * zDir);

    xDir = vectorLength * xStartDir * maxDist + (xDir / vectorLength) * (Math.random() * maxDist * 2 - maxDist) + xOffset + xStart;
    yDir = vectorLength * yStartDir * maxDist + (yDir / vectorLength) * (Math.random() * maxDist * 2 - maxDist) + yOffset + yStart;
    zDir = vectorLength * zStartDir * maxDist + (zDir / vectorLength) * (Math.random() * maxDist * 2 - maxDist) + zOffset + zStart;


    particles[i] = {
      "x1": xStart,
      "y1": yStart,
      "z1": zStart,
      "x2": xDir,
      "y2": yDir,
      "z2": zDir,
      "startAngle": Math.random() * 360,
      "speedAngle": (Math.random() * 4 - 2) * (250),
    };



  }


  let explosionAnimation = {
    time: timeFunction,
    "parent": (parentId === "scene") ? undefined : parentId,
    "start": startTime, "duration": 200,
    "image": particleTexture,
    textureProperties: [{}, { minFilter: 'NearestMipmapNearestFilter', magFilter: 'LinearFilter' }],
    position: [{ x: posX, y: posY, z: posZ }],
    "perspective": "3d",
    "billboard": true,
    "scale": [{ "uniform3d": .60 }],
    "material": {
      "blending": blendingMode,
      "transparent": true,
      "depthWrite": blendingMode == false
    },
    "instancer": {
      "count": particles.length,
      "runInstanceFunction": (properties) => {

        const i = properties.index;
        //const count = properties.count;
        //const time = properties.time;
        let object = properties.object;
        let color = properties.color;
        let angle = properties.angle;

        const scale = particleScale;
        object.scale.x = scale;
        object.scale.y = scale;
        object.scale.z = scale;

        const particle = particles[i];

        const now = getSceneTimeFromStart();

        angle.degreesZ = particle.startAngle + now * (particle.speedAngle);

        const percent = (now - startTime) / duration;

        const mix = Math.log((percent * 7.0 + 1.0)) / 3;
        object.position.x = Utils.mix(particle.x1, particle.x2, mix);
        object.position.y = Utils.mix(particle.y1, particle.y2, mix);
        object.position.z = Utils.mix(particle.z1, particle.z2, mix);
        color.a = 1.0 - percent * 2;
        color.r = color.a;
        color.g = color.a;
        color.b = color.a;
      }
    }
  }

  this.loader.addAnimation(explosionAnimation);
}