<template>
  <div :class="[b(),className]"
       :style="styleSizeName"
       @mouseenter="handleMouseEnter"
       @mouseleave="handleMouseLeave"
       @dblclick="handleDblClick"
       @click="handleClick">
    <div v-loading="loading"
         element-loading-text="模型加载中"
         element-loading-background="rgba(0, 0, 0, 0)">
      <div ref="threejs"
           :style="styleSizeName"
           v-if="isThreeJs"></div>
      <component v-else
                 :key="reload"
                 :style="styleSizeName"
                 :scale="scale"
                 :backgroundAlpha="0"
                 backgroundColor="#000"
                 :rotation="rotation"
                 :is="type"
                 :src="src"
                 @load="onLoad" />
    </div>
  </div>
</template>

<script>

import { getObj } from '@/api/components'
import create from "../../create";
import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
import { ModelCollada, ModelFbx, ModelGltf, ModelThree, ModelObj, ModelPly, ModelStl, } from 'vue-3d-model';

export default create({
  name: "3dmodel",
  components: {
    ModelCollada, ModelFbx, ModelGltf, ModelThree, ModelObj, ModelPly, ModelStl,
  },
  data () {
    return {
      json: {},
      reload: Math.random(),
      loading: false,
      check: null,
      rotation: {
        x: 0,
        y: 0,
        z: 0,
      },
    };
  },
  watch: {
    scale: {
      handler () {
        this.init()
      },
      immediate: true,
      deep: true
    },
    width: {
      handler () {
        this.init()
      },
      immediate: true,
    },
    height: {
      handler () {
        this.init()
      },
      immediate: true,
    },
    x: {
      handler () {
        this.rotation.x = this.option.x || 0
        this.init()
      },
      immediate: true,
    },
    y: {
      handler () {
        this.rotation.y = this.option.y || 0
        this.init()
      },
      immediate: true,
    },
    z: {
      handler () {
        this.rotation.z = this.option.z || 0
        this.init()
      },
      immediate: true,
    },
    rotate: {
      handler () {
        this.init()
      },
      immediate: true,
    },
    ids: {
      handler () {
        this.getData()
      },
      immediate: true,
    },
    src: {
      handler () {
        this.init()
      },
      immediate: true,
    },
    type: {
      handler () {
        this.init()
      },
      immediate: true,
    }
  },
  computed: {
    isThreeJs () {
      return this.ids
    },
    ids () {
      return this.option.id
    },
    scale () {
      return {
        x: this.option.scale || 1,
        y: this.option.scale || 1,
        z: this.option.scale || 1,
      }
    },
    rotate () {
      return this.option.rotate
    },
    x () {
      return this.option.x
    },
    y () {
      return this.option.y
    },
    z () {
      return this.option.z
    },
    src () {
      return this.option.src
    },
    type () {
      return this.option.type
    }
  },
  mounted () {
    this.getData()
  },
  methods: {
    getData () {
      if (!this.ids) return
      this.showLoad()
      getObj(this.ids).then(res => {
        const data = res.data.data;
        this.json = JSON.parse(data.content)
        this.initThreejs()
      })
    },
    init () {
      this.isThreeJs ? this.initThreejs() : this.init3D()
    },
    initThreejs () {
      if (!this.$refs.threejs || !this.json.scene) return
      let json = this.json
      let sceneList = []
      const scene = new THREE.Scene();
      const camera = new THREE.PerspectiveCamera(50, this.width / this.height, 0.01, 1000);
      const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
      renderer.setSize(this.width, this.height);
      this.$refs.threejs.innerHTML = '';
      this.$refs.threejs.appendChild(renderer.domElement);
      // 设置相机位置
      camera.position.set(this.option.x, this.option.y, this.option.y);
      camera.lookAt(0, 0, 0);
      camera.updateProjectionMatrix(); // 更新投影矩阵

      // 解析并添加场景对象
      const loader = new THREE.ObjectLoader();
      loader.parse(json.scene, object => {
        sceneList.push(object)
        scene.add(object);
      });

      const controls = new OrbitControls(camera, renderer.domElement);
      controls.enableDamping = true; // 启用阻尼（惯性）
      controls.dampingFactor = 0.25; // 阻尼因子

      // 渲染循环
      const animate = () => {
        requestAnimationFrame(animate);
        controls.update(); // 更新控制器
        sceneList.forEach(ele => {
          ele.scale.set(this.scale.x, this.scale.y, this.scale.z);
          if (this.rotate) ele.rotation[this.option.position] += 0.1
        })
        renderer.render(scene, camera);
      };
      animate();
      this.hideLoad()
    },
    init3D () {
      this.$nextTick(() => {
        this.reload = Math.random();
        this.showLoad()
      })
    },
    showLoad () {
      this.loading = true
    },
    hideLoad () {
      this.loading = false
    },
    onLoad (d) {
      if (this.check) cancelAnimationFrame(this.check);
      if (this.rotate) this.rotateFun()
      this.hideLoad();
    },
    rotateFun () {
      this.check = requestAnimationFrame(this.rotateFun);
      this.rotation[this.option.position || 'y'] += 0.01;
    },
  }
});

</script>