<template>
  <div class="wave"></div>
</template>

<script>
import * as THREE from "three";
import $ from "jquery";

let scene, camera, renderer, particles;

export default {
  // 名称
  name: "wave",
  // 使用组件
  components: {},
  // 传入参数
  props: {},
  // 自定义事件
  emits: {},
  // 数据
  data() {
    return {
      SEPARATION: 100,
      AMOUNTX: 100,
      AMOUNTY: 100,
      count: 0,
      mouseX: 0,
      mouseY: -400,
      windowHalfX: window.innerWidth / 2,
      windowHalfY: window.innerHeight / 2,
    };
  },
  // 函数
  methods: {
    init() {
      camera = new THREE.PerspectiveCamera(
        50,
        window.innerWidth / window.innerHeight,
        1,
        10000
      );
      camera.position.z = 1000;
      scene = new THREE.Scene();
      const numParticles = this.AMOUNTX * this.AMOUNTY;
      const positions = new Float32Array(numParticles * 3);
      const scales = new Float32Array(numParticles);
      let i = 0,
        j = 0;
      for (let ix = 0; ix < this.AMOUNTX; ix++) {
        for (let iy = 0; iy < this.AMOUNTY; iy++) {
          positions[i] =
            ix * this.SEPARATION - (this.AMOUNTX * this.SEPARATION) / 2; // x
          positions[i + 1] = 0; // y
          positions[i + 2] =
            iy * this.SEPARATION - (this.AMOUNTY * this.SEPARATION) / 2; // z
          scales[j] = 1;
          i += 3;
          j++;
        }
      }
      const geometry = new THREE.BufferGeometry();
      geometry.setAttribute(
        "position",
        new THREE.BufferAttribute(positions, 3)
      );
      geometry.setAttribute("scale", new THREE.BufferAttribute(scales, 1));
      const material = new THREE.ShaderMaterial({
        uniforms: {
          color: {
            value: new THREE.Color(
              this.$store.state.themeName === "dark" ? 0x05bb4c : 0x36348e
            ),
          },
        },
        vertexShader: `attribute float scale;
                        void main() {
                            vec4 mvPosition = modelViewMatrix * vec4( position, 2.0 );
                            gl_PointSize = scale * ( 200.0 / - mvPosition.z );
                            gl_Position = projectionMatrix * mvPosition;
                        }`,
        fragmentShader: `uniform vec3 color;
                        void main() {
                            if ( length( gl_PointCoord - vec2( 0.5, 0.5 ) ) > 0.475 ) discard;
                            gl_FragColor = vec4( color, 0.7 );
                        }`,
        transparent: true,
      });
      particles = new THREE.Points(geometry, material);
      scene.add(particles);
      renderer = new THREE.WebGLRenderer({
        antialias: true,
        alpha: true,
      });
      renderer.setSize(window.innerWidth, window.innerHeight);
      renderer.setPixelRatio(window.devicePixelRatio);
      renderer.setAnimationLoop(this.render);
      this.$el.appendChild(renderer.domElement);
    },
    render() {
      camera.position.x += (this.mouseX - camera.position.x) * 0.05;
      camera.position.y += (-this.mouseY - camera.position.y) * 0.05;
      camera.lookAt(scene.position);
      const positions = particles.geometry.attributes.position.array;
      const scales = particles.geometry.attributes.scale.array;
      let i = 0,
        j = 0;
      for (let ix = 0; ix < this.AMOUNTX; ix++) {
        for (let iy = 0; iy < this.AMOUNTY; iy++) {
          positions[i + 1] =
            Math.sin((ix + this.count) * 0.3) * 50 +
            Math.sin((iy + this.count) * 0.5) * 50;
          scales[j] =
            (Math.sin((ix + this.count) * 0.3) + 1) * 20 +
            (Math.sin((iy + this.count) * 0.5) + 1) * 20;
          i += 3;
          j++;
        }
      }
      particles.geometry.attributes.position.needsUpdate = true;
      particles.geometry.attributes.scale.needsUpdate = true;
      renderer.render(scene, camera);
      this.count += 0.1;
    },
  },
  // 生命周期钩子
  beforeCreate() {
    // 创建前
  },
  created() {
    // 创建后
  },
  beforeMount() {
    // 渲染前
  },
  mounted() {
    // 渲染后
    camera = null;
    scene = null;
    renderer = null;
    this.init();
  },
  beforeUpdate() {
    // 数据更新前
  },
  updated() {
    // 数据更新后
  },
  beforeUnmount() {
    // 销毁前
    renderer.setAnimationLoop(null);
    camera = null;
    scene = null;
    renderer = null;
  },

  watch: {
    "$store.state.themeName"() {
      $(".wave").empty();
      renderer.setAnimationLoop(null);
      this.init();
    },
  },
};
</script>

<style lang="less">
.wave {
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 60%;
  z-index: -1;
  overflow: hidden;
}
</style>
