<template>
  <div class="coalesce-bg">
    <div class="content--canvas"></div>
  </div>
</template>
<script>
import SimplexNoise from "simplex-noise"
import {
  cos,
  randIn,
  sin,
  rand,
  TAU,
  TO_RAD,
  HALF_PI,
  fadeIn,
  fadeInOut,
  dist,
  angle,
  lerp
} from "../engines/three/wrapengine/mathlib"

export default {
  name: "BgAether",
  mounted() {
    const particleCount = 1000
    const spawnRadius = 100
    const noiseSteps = 6

    let canvas
    let ctx
    let center
    let tick
    let simplex
    let positions
    let velocities
    let speeds
    let lifeSpans
    let sizes
    let hues
    let container

    this.setup = () => {
      tick = 0
      center = []
      this.createCanvas()
      this.createParticles()
      this.draw()
    }

    this.createParticles = () => {
      simplex = new SimplexNoise()
      positions = new Float32Array(particleCount * 2)
      velocities = new Float32Array(particleCount * 2)
      lifeSpans = new Float32Array(particleCount * 2)
      speeds = new Float32Array(particleCount)
      hues = new Float32Array(particleCount)
      sizes = new Float32Array(particleCount)

      let i

      for (i = 0; i < particleCount * 2; i += 2) {
        this.initParticle(i)
      }
    }

    this.initParticle = (i) => {
      let iy, ih, rd, rt, cx, sy, x, y, s, rv, vx, vy, t, h, si, l, ttl

      iy = i + 1
      ih = (0.5 * i) | 0
      rd = rand(spawnRadius)
      rt = rand(TAU)
      cx = cos(rt)
      sy = sin(rt)
      x = center[0] + cx * rd
      y = center[1] + sy * rd
      rv = randIn(0.1, 1)
      s = randIn(1, 8)
      vx = rv * cx * 0.1
      vy = rv * sy * 0.1
      si = randIn(0.1, 1)
      h = randIn(160, 260)
      l = 0
      ttl = randIn(50, 200)

      positions[i] = x
      positions[iy] = y
      velocities[i] = vx
      velocities[iy] = vy
      speeds[ih] = s
      hues[ih] = h
      sizes[ih] = si
      lifeSpans[i] = l
      lifeSpans[iy] = ttl
    }

    this.drawParticle = (i) => {
      let iy, ih, x, y, n, tx, ty, s, vx, vy, h, si, l, dl, ttl, c

      iy = i + 1
      ih = (0.5 * i) | 0
      x = positions[i]
      y = positions[iy]
      n =
          simplex.noise3D(x * 0.0025, y * 0.0025, tick * 0.0005) *
          TAU *
          noiseSteps
      vx = lerp(velocities[i], cos(n), 0.05)
      vy = lerp(velocities[iy], sin(n), 0.05)
      s = speeds[ih]
      tx = x + vx * s
      ty = y + vy * s
      h = hues[ih]
      si = sizes[ih]
      l = lifeSpans[i]
      ttl = lifeSpans[iy]
      dl = fadeInOut(l, ttl)
      c = `hsla(${h},50%,60%,${dl})`

      l++

      ctx.a.save()
      ctx.a.lineWidth = dl * si + 1
      ctx.a.strokeStyle = c
      ctx.a.beginPath()
      ctx.a.moveTo(x, y)
      ctx.a.lineTo(tx, ty)
      ctx.a.stroke()
      ctx.a.closePath()
      ctx.a.restore()

      positions[i] = tx
      positions[iy] = ty
      velocities[i] = vx
      velocities[iy] = vy
      lifeSpans[i] = l;

      (this.checkBounds(x, y) || l > ttl) && this.initParticle(i)
    }

    this.checkBounds = (x, y) => {
      return x > canvas.a.width || x < 0 || y > canvas.a.height || y < 0
    }

    this.createCanvas = () => {
      container = document.querySelector(".content--canvas")
      canvas = {
        a: document.createElement("canvas"),
        b: document.createElement("canvas")
      }
      canvas.b.style = `
		position: absolute;
		top: 0;
		left: 0;
		width: 100%;
		height: 100%;
    `
      container.appendChild(canvas.b)

      ctx = {
        a: canvas.a.getContext("2d"),
        b: canvas.b.getContext("2d")
      }
      this.resize()
    }

    this.resize = () => {
      const { innerWidth, innerHeight } = window

      canvas.a.width = innerWidth
      canvas.a.height = innerHeight

      ctx.a.drawImage(canvas.b, 0, 0)

      canvas.b.width = innerWidth
      canvas.b.height = innerHeight

      ctx.b.drawImage(canvas.a, 0, 0)

      center[0] = 0.5 * canvas.a.width
      center[1] = 0.5 * canvas.a.height
    }

    this.draw = () => {
      tick++
      ctx.a.clearRect(0, 0, canvas.a.width, canvas.a.height)

      ctx.b.fillStyle = "rgba(0,0,0,0.1)"
      ctx.b.fillRect(0, 0, canvas.b.width, canvas.b.height)

      let i

      for (i = 0; i < particleCount * 2; i += 2) {
        this.drawParticle(i)
      }

      ctx.b.save()
      ctx.b.filter = "blur(8px)"
      ctx.b.globalCompositeOperation = "lighten"
      ctx.b.drawImage(canvas.a, 0, 0)
      ctx.b.restore()

      ctx.b.save()
      ctx.b.globalCompositeOperation = "lighter"
      ctx.b.drawImage(canvas.a, 0, 0)
      ctx.b.restore()
      if (!this.cancel) {
        window.requestAnimationFrame(this.draw)
      }
    }

    setTimeout(() => {
      this.setup()
    }, 100)
    window.addEventListener("resize", this.resize)
  },
  beforeDestroy() {
    this.cancel = true
    window.removeEventListener("resize", this.resize)
  }
}
</script>
<style scoped>
</style>
