<template>
    <div class="c-shader" ref="container"></div>
</template>

<script>
import gsap from "gsap";
import * as THREE from "three";
import * as Stats from "stats.js";

import colorVertex from "@/assets/shader/color_vertex.glsl";
import colorFrag from "@/assets/shader/color_fragment.glsl";
import pos1024 from "@/assets/layout/1024.js";
import { GUI } from "three/examples/jsm/libs/dat.gui.module.js";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
import { EffectComposer } from "three/examples/jsm/postprocessing/EffectComposer.js";
import { RenderPass } from "three/examples/jsm/postprocessing/RenderPass.js";
import { ShaderPass } from "three/examples/jsm/postprocessing/ShaderPass.js";
import { UnrealBloomPass } from "three/examples/jsm/postprocessing/UnrealBloomPass.js";

export default {
    name: "color",
    props: {
        msg: String,
    },
    data() {
        return {
            remaining: 50,
            container: null,
            camera: null,
            scene: null,
            renderer: null,
            mouse: new THREE.Vector2(),
            raycaster: new THREE.Raycaster(),
            // gui: new GUI(),

            ENTIRE_SCENE: 0,
            BLOOM_SCENE: 1,
            materials: {},
            params: {
                exposure: 1,
                bloomStrength: 5,
                bloomThreshold: 0,
                bloomRadius: 0,
                scene: "Scene with Glow",
            },
        };
    },
    created() {},
    mounted() {
        this.initStage();
        this.addAnimation();
    },
    methods: {
        initStage() {
            //基础参数
            this.container = this.$refs.container;
            this.camera = new THREE.Camera();
            this.camera.position.z = 1;
            this.scene = new THREE.Scene();

            this.bloomLayer = new THREE.Layers();
            this.bloomLayer.set(this.BLOOM_SCENE);

            this.darkMaterial = new THREE.MeshBasicMaterial({ color: "black" });

            // 定义 webglrender
            this.renderer = new THREE.WebGLRenderer({ antialias: true });
            this.renderer.setPixelRatio(window.devicePixelRatio);
            this.renderer.setSize(window.innerWidth, window.innerHeight);
            this.renderer.toneMapping = THREE.ReinhardToneMapping;
            if (!document.getElementById("webgl")) {
                this.renderer.domElement.id = "webgl";
                this.container.appendChild(this.renderer.domElement);
            }

            // 定义相机
            this.camera = new THREE.PerspectiveCamera(
                40,
                window.innerWidth / window.innerHeight,
                1,
                2000
            );
            this.camera.position.set(
                0,
                0,
                window.deviceInfo.device == "PC" ? 500 : 1000
            );
            this.camera.lookAt(0, 0, 0);

            // 定义操控
            this.controls = new OrbitControls(
                this.camera,
                this.renderer.domElement
            );
            this.controls.maxPolarAngle = Math.PI * 0.5;
            this.controls.minDistance = 1;
            this.controls.maxDistance = 1500;
            this.controls.addEventListener("change", this.render);

            // 添加全局环境光
            this.scene.add(new THREE.AmbientLight(0x404040));

            this.renderScene = new RenderPass(this.scene, this.camera);

            this.bloomPass = new UnrealBloomPass(
                new THREE.Vector2(window.innerWidth, window.innerHeight),
                1.5,
                0.4,
                0.85
            );
            this.bloomPass.threshold = this.params.bloomThreshold;
            this.bloomPass.strength = this.params.bloomStrength;
            this.bloomPass.radius = this.params.bloomRadius;

            this.bloomComposer = new EffectComposer(this.renderer);
            this.bloomComposer.renderToScreen = false;
            this.bloomComposer.addPass(this.renderScene);
            this.bloomComposer.addPass(this.bloomPass);

            this.finalPass = new ShaderPass(
                new THREE.ShaderMaterial({
                    uniforms: {
                        baseTexture: { value: null },
                        bloomTexture: {
                            value: this.bloomComposer.renderTarget2.texture,
                        },
                    },
                    vertexShader: colorVertex,
                    fragmentShader: colorFrag,
                    defines: {},
                }),
                "baseTexture"
            );
            this.finalPass.needsSwap = true;

            this.finalComposer = new EffectComposer(this.renderer);
            this.finalComposer.addPass(this.renderScene);
            this.finalComposer.addPass(this.finalPass);

            // 添加点击事件
            window.addEventListener("pointerdown", this.onPointerDown);

            // this.gui
            //     .add(this.params, "scene", [
            //         "Scene with Glow",
            //         "Glow only",
            //         "Scene only",
            //     ])
            //     .onChange((value) => {
            //         switch (value) {
            //             case "Scene with Glow":
            //                 this.bloomComposer.renderToScreen = false;
            //                 break;
            //             case "Glow only":
            //                 this.bloomComposer.renderToScreen = true;
            //                 break;
            //             case "Scene only":
            //                 // nothing to do
            //                 break;
            //         }

            //         this.render();
            //     });

            // this.folder = this.gui.addFolder("Bloom Parameters");

            // this.folder
            //     .add(this.params, "exposure", 0.1, 2)
            //     .onChange((value) => {
            //         this.renderer.toneMappingExposure = Math.pow(value, 4.0);
            //         this.render();
            //     });

            // this.folder
            //     .add(this.params, "bloomThreshold", 0.0, 1.0)
            //     .onChange((value) => {
            //         this.bloomPass.threshold = Number(value);
            //         this.render();
            //     });

            // this.folder
            //     .add(this.params, "bloomStrength", 0.0, 10.0)
            //     .onChange((value) => {
            //         this.bloomPass.strength = Number(value);
            //         this.render();
            //     });

            // this.folder
            //     .add(this.params, "bloomRadius", 0.0, 1.0)
            //     .step(0.01)
            //     .onChange((value) => {
            //         this.bloomPass.radius = Number(value);
            //         this.render();
            //     });

            // 设置场景
            this.setupScene();
            // 循环动画
            this.animate();
            // 自动缩放

            window.addEventListener("resize", this.onWindowResize);
            this.onWindowResize();
        },
        onPointerDown(event) {
            this.mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
            this.mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;

            this.raycaster.setFromCamera(this.mouse, this.camera);
            this.intersects = this.raycaster.intersectObjects(
                this.group.children,
                false
            );
            if (this.intersects.length > 0) {
                const object = this.intersects[0].object;
                gsap.to(object.scale, {
                    x: 0,
                    y: 0,
                    z: 0,
                    onUpdate: () => {
                        this.render();
                    },
                });
                object.layers.toggle(this.BLOOM_SCENE);
                this.render();
            }
        },
        onWindowResize(event) {
            const width = window.innerWidth;
            const height = window.innerHeight;

            this.camera.aspect = width / height;
            this.camera.updateProjectionMatrix();

            this.renderer.setSize(width, height);

            this.bloomComposer.setSize(width, height);
            this.finalComposer.setSize(width, height);

            this.render();
        },
        setupScene() {
            this.scene.traverse(this.disposeMaterial);
            this.scene.children.length = 0;

            const geometry = new THREE.IcosahedronGeometry(1, 15);
            this.group = new THREE.Group();
            for (let ii = 0; ii < 2; ii++) {
                pos1024.origin.forEach((item, index) => {
                    item.forEach((t, i) => {
                        if (t == 0) {
                            const color = new THREE.Color();
                            color.setHSL(
                                Math.random(),
                                0.7,
                                Math.random() * 0.2 + 0.05
                            );
                            const material = new THREE.MeshBasicMaterial({
                                color: color,
                            });
                            const sphere = new THREE.Mesh(geometry, material);

                            sphere.position.x = i * 10 - (item.length / 2) * 10;
                            sphere.position.y =
                                -index * 10 + (pos1024.origin.length / 2) * 10;
                            sphere.position.z = ii * 5;
                            // sphere.position
                            //     .normalize()
                            //     .multiplyScalar(Math.random() * 4.0 + 2);
                            sphere.scale.setScalar(Math.random() * 4 + 3);
                            this.scene.add(sphere);

                            // if (Math.random() < 0.25)
                            sphere.layers.enable(this.BLOOM_SCENE);

                            this.group.add(sphere);
                        }
                    });
                });
            }

            // for (let i = 0; i < this.remaining; i++) {
            //     const color = new THREE.Color();
            //     color.setHSL(Math.random(), 0.7, Math.random() * 0.2 + 0.05);

            //     const material = new THREE.MeshBasicMaterial({ color: color });
            //     const sphere = new THREE.Mesh(geometry, material);
            //     sphere.position.x = Math.random() * 30 - 15;
            //     sphere.position.y = Math.random() * 30 - 15;
            //     sphere.position.z = Math.random() * 30 - 15;
            //     sphere.position
            //         .normalize()
            //         .multiplyScalar(Math.random() * 5.0 + 2.5);
            //     sphere.scale.setScalar(Math.random() * Math.random() + 0.5);
            //     this.scene.add(sphere);

            //     // if (Math.random() < 0.25)
            //     sphere.layers.enable(this.BLOOM_SCENE);

            //     this.group.add(sphere);
            // }
            this.scene.add(this.group);
            this.render();
        },
        disposeMaterial(obj) {
            if (obj.material) {
                obj.material.dispose();
            }
        },
        animate() {
            requestAnimationFrame(this.animate);
            this.render();
        },
        render() {
            switch (this.params.scene) {
                case "Scene only":
                    this.renderer.render(this.scene, this.camera);
                    break;
                case "Glow only":
                    this.renderBloom(false);
                    break;
                case "Scene with Glow":
                default:
                    // render scene with bloom
                    this.renderBloom(true);

                    // render the entire scene, then render bloom scene on top
                    this.finalComposer.render();
                    break;
            }
            // this.renderer.render(this.scene, this.camera);
        },
        renderBloom(mask) {
            if (mask === true) {
                this.scene.traverse(this.darkenNonBloomed);
                this.bloomComposer.render();
                this.scene.traverse(this.restoreMaterial);
            } else {
                this.camera.layers.set(this.BLOOM_SCENE);
                this.bloomComposer.render();
                this.camera.layers.set(this.ENTIRE_SCENE);
            }
        },
        darkenNonBloomed(obj) {
            if (obj.isMesh && this.bloomLayer.test(obj.layers) === false) {
                this.materials[obj.uuid] = obj.material;
                obj.material = this.darkMaterial;
            }
        },
        restoreMaterial(obj) {
            if (this.materials[obj.uuid]) {
                obj.material = this.materials[obj.uuid];
                delete this.materials[obj.uuid];
            }
        },
        addAnimation() {
            // 自旋转
            gsap.to(this.group.rotation, {
                y: -Math.PI * 2,
                x: 0.1,
                duration: 5,
                // yoyo: true,
                // repeat: -1,
                onUpdate: () => {
                    // this.renderer.toneMappingExposure = Math.pow(
                    //     this.params.exposure,
                    //     4.0
                    // );
                    // this.render();
                    // console.log(this.params.scene);
                },
            });
            // 球体自动
            this.group.children.map((item, index) => {
                gsap.to(item.scale, {
                    x: "+=.5",
                    y: "+=.5",
                    z: "+=.5",
                    stagger: 0.01,
                    duration: 1,
                    ease: "none",
                    yoyoEase: "none",
                    yoyo: true,
                    repeat: 10,
                });

                let op = item.position;
                gsap.fromTo(
                    item.position,
                    {
                        x: () => {
                            return Math.random() * 100 - 50;
                        },
                        y: () => {
                            return Math.random() * 100 - 50;
                        },
                        z: () => {
                            return Math.random() * 100 - 20;
                        },
                    },
                    {
                        x: op.x,
                        y: op.y,
                        z: op.z,
                        duration: 5,
                        onUpdate: () => {
                            // if (index == 1) this.render();
                        },
                    }
                );
            });

            setTimeout(() => {
                let iii = 0;
                for (let ii = 0; ii < 2; ii++) {
                    pos1024.ready.forEach((item, index) => {
                        item.forEach((t, i) => {
                            if (t == 0) {
                                let position = {};
                                position.x = i * 10 - (item.length / 2) * 10;
                                position.y =
                                    -index * 10 +
                                    (pos1024.ready.length / 2) * 10;
                                position.z = ii * 10;
                                gsap.to(this.group.children[iii].position, {
                                    x: position.x,
                                    y: position.y,
                                    z: position.z,
                                    duration: 1,
                                });
                                iii++;
                            }
                        });
                    });
                }

                this.group.children.forEach((item, index) => {
                    if (index >= iii) {
                        gsap.to(item.position, {
                            x: 10000,
                            y: 10000,
                            z: 10000,
                        });
                        // gsap.to(item.scale, { x: 0, y: 0, z: 0 });
                    } else {
                        gsap.to(item.position, {
                            x: Math.random() * 1000 - 500,
                            y: Math.random() * 1000 - 500,
                            z: Math.random() * 1000,
                            duration: 2,
                            delay: 4,
                        });
                        gsap.to(item.scale, {
                            x: 0,
                            y: 0,
                            z: 0,
                            duration: 2.5,
                            delay: 4,
                        });
                    }
                });
            }, 6000);
            // for (let ii = 0; ii < 2; ii++) {

            // }

            if (window.deviceInfo.device !== "PC") {
                gsap.to(this.camera.position, {
                    z: 1200,
                    delay: 1,
                });
                gsap.to(this.camera.position, {
                    z: 1400,
                    delay: 6.5,
                });
            }

            // 光闪烁
            // gsap.to(this.params, {
            //     exposure: 1.1,
            //     duration: 2,
            //     yoyo: true,
            //     repeat: -1,
            //     onUpdate: () => {
            //         this.renderer.toneMappingExposure = Math.pow(
            //             this.params.exposure,
            //             4.0
            //         );
            //         this.render();
            //         // console.log(this.params.scene);
            //     },
            // });
        },
    },
};
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="less">
.c-shader {
    width: 100vw;
    height: 100vh;
    position: relative;
    z-index: 0;
    .select-btn {
        // background-color: #fff;
        .paCenterBottom(2%,50%,auto,10);
    }
}
</style>
