<!-- resources/views/mockup.blade.php -->
<!doctype html>
<html>

<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <title>3D Label Mockup</title>
    <style>
        html,
        body {
            height: 100%;
            margin: 0;
            background: #f6f7fb;
        }

        #app {
            height: 100vh;
        }

        .toolbar {
            position: fixed;
            top: 12px;
            left: 12px;
            z-index: 10;
            display: flex;
            gap: 8px;
            background: #fff;
            padding: 8px 10px;
            border-radius: 12px;
            box-shadow: 0 8px 24px rgba(0, 0, 0, .06);
            font-family: ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto;
            pointer-events: none;
            /* jangan blokir canvas */
        }

        .toolbar * {
            pointer-events: auto;
        }

        button {
            border: 0;
            padding: 8px 12px;
            border-radius: 10px;
            background: #111;
            color: #fff;
            cursor: pointer;
        }

        #app canvas {
            display: block;
            outline: none;
        }
    </style>
</head>

<body>
    <div class="toolbar">
        <button id="snapshot">Export PNG</button>
    </div>
    <div id="app"></div>

    <script type="module" data-cfasync="false">
        import * as THREE from "https://esm.run/three@0.160.0";
        import {
            OrbitControls
        } from "https://esm.run/three@0.160.0/examples/jsm/controls/OrbitControls.js";

        // ---------- BASIC ----------
        const app = document.getElementById('app');
        const scene = new THREE.Scene();
        scene.background = new THREE.Color(0xf6f7fb);

        const camera = new THREE.PerspectiveCamera(35, app.clientWidth / app.clientHeight, 0.1, 100);
        camera.position.set(0, 0.5, 3.5); // nilai awal; nanti di-fit otomatis

        const renderer = new THREE.WebGLRenderer({
            antialias: true,
            preserveDrawingBuffer: true
        });
        renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
        renderer.setSize(app.clientWidth, app.clientHeight);
        renderer.domElement.style.touchAction = 'none';
        app.appendChild(renderer.domElement);

        const controls = new OrbitControls(camera, renderer.domElement);
        controls.enableDamping = true;
        controls.minPolarAngle = Math.PI / 6; // 30°
        controls.maxPolarAngle = Math.PI / 2; // 90°
        controls.minDistance = 1.8;
        controls.maxDistance = 6.0;

        // ---------- LIGHTS ----------
        scene.add(new THREE.HemisphereLight(0xffffff, 0x8899aa, 0.8));
        const dir = new THREE.DirectionalLight(0xffffff, 0.9);
        dir.position.set(2, 3, 2);
        scene.add(dir);
        scene.add(new THREE.AmbientLight(0xffffff, 0.9));

        // ---------- MATERIALS ----------
        const whiteGloss = new THREE.MeshPhysicalMaterial({
            color: 0xffffff,
            roughness: 0.2,
            metalness: 0.0,
            clearcoat: 0.2,
            clearcoatRoughness: 0.05
        });
        const chrome = new THREE.MeshPhysicalMaterial({
            color: 0xdddddd,
            roughness: 0.1,
            metalness: 1.0
        });
        const labelMat = new THREE.MeshBasicMaterial({
            color: 0xffffff,
            transparent: true,
            side: THREE.DoubleSide
        });

        // ---------- GEOMETRIES ----------
        const bodyRadius = 0.13,
            bodyHeight = 2.4,
            labelHeight = 2;

        const bodyGeo = new THREE.CylinderGeometry(bodyRadius, bodyRadius, bodyHeight, 96, 1, true);
        const body = new THREE.Mesh(bodyGeo, whiteGloss);

        const labelRadius = bodyRadius * 1.0015;
        const labelGeo = new THREE.CylinderGeometry(labelRadius, labelRadius, labelHeight, 256, 1, true);
        const labelMesh = new THREE.Mesh(labelGeo, labelMat);
        labelMesh.position.y = 0;

        const topGeo = new THREE.SphereGeometry(bodyRadius * 1.0, 96, 48, 0, Math.PI * 2, 0, Math.PI / 2);
        const top = new THREE.Mesh(topGeo, whiteGloss);
        top.position.y = bodyHeight / 2;

        //ini cincin item
        // const ringGeo = new THREE.TorusGeometry(bodyRadius * 0.98, 0.015, 24, 128);
        // const ring = new THREE.Mesh(ringGeo, chrome);
        // ring.rotation.x = Math.PI / 2;
        // ring.position.y = bodyHeight / 2 - 0.03;

        const bottomGeo = new THREE.SphereGeometry(bodyRadius * 0.98, 96, 48, 0, Math.PI * 2, Math.PI / 2, Math.PI / 2);
        const bottom = new THREE.Mesh(bottomGeo, whiteGloss);
        bottom.position.y = -bodyHeight / 2;

        // group semua bagian botol (ground jangan ikut)
        const bottle = new THREE.Group();
        // bottle.add(body, labelMesh, top, ring, bottom);
        bottle.add(body, labelMesh, top, bottom);
        scene.add(bottle);

        // rotate botol 180° supaya label kelihatan
        bottle.rotation.y = Math.PI;


        // (opsional) kalau mau putar seluruh model 180°
        // scene.rotation.y = Math.PI;

        // Ground tetap di scene (di luar group), biar tidak mempengaruhi tinggi bottle
        const groundGeo = new THREE.CircleGeometry(1.2, 128);
        const groundMat = new THREE.MeshBasicMaterial({
            color: 0xE7E9EF
        });
        const ground = new THREE.Mesh(groundGeo, groundMat);
        ground.rotation.x = -Math.PI / 2;
        ground.position.y = -bodyHeight / 2 - 0.35;
        scene.add(ground);

        // ---------- TEXTURE ----------
        const loader = new THREE.TextureLoader();
        loader.crossOrigin = 'anonymous';

        const params = new URLSearchParams(window.location.search);
        const labelFromURL = params.get('image');
        const rotateDeg = parseFloat(params.get('r') || '90'); // default 90°

        function setLabelTexture(url) {
            loader.load(url, (tex) => {
                tex.colorSpace = THREE.SRGBColorSpace;
                tex.minFilter = THREE.LinearMipmapLinearFilter;
                tex.wrapS = THREE.RepeatWrapping;
                tex.wrapT = THREE.ClampToEdgeWrapping;

                if (!isNaN(rotateDeg) && rotateDeg !== 0) {
                    tex.center.set(0.5, 0.5);
                    tex.rotation = rotateDeg * Math.PI / 180;
                }
                labelMat.map = tex;
                labelMat.needsUpdate = true;
                renderOnce();
            });
        }
        if (labelFromURL) setLabelTexture(labelFromURL);

        // ---------- AUTO FRAMING ----------
        function fitCameraToObject(camera, controls, object, {
            offset = 1.22,
            biasY = -0.08
        } = {}) {
            const box = new THREE.Box3().setFromObject(object);
            const size = box.getSize(new THREE.Vector3());
            const center = box.getCenter(new THREE.Vector3());

            // geser fokus sedikit ke bawah agar bawah tidak kepotong
            center.y += size.y * biasY;

            const fov = THREE.MathUtils.degToRad(camera.fov);
            const fitHeightDist = (size.y / 2) / Math.tan(fov / 2);
            const fitWidthDist = (size.x / 2) / (Math.tan(fov / 2) * camera.aspect);
            const distance = offset * Math.max(fitHeightDist, fitWidthDist);

            // arah dari kamera ke target saat ini
            const dir = new THREE.Vector3()
                .subVectors(camera.position, controls.target)
                .normalize();

            camera.position.copy(dir.multiplyScalar(distance).add(center));
            controls.target.copy(center);
            controls.update();
        }

        // panggil setelah bottle ditambahkan
        fitCameraToObject(camera, controls, bottle, {
            offset: 1.22,
            biasY: -0.08
        });

        // ---------- SNAPSHOT ----------
        document.getElementById('snapshot').addEventListener('click', () => {
            const a = document.createElement('a');
            a.href = renderer.domElement.toDataURL('image/png');
            a.download = 'mockup.png';
            a.click();
        });

        // ---------- RESIZE ----------
        window.addEventListener('resize', () => {
            camera.aspect = app.clientWidth / app.clientHeight;
            camera.updateProjectionMatrix();
            renderer.setSize(app.clientWidth, app.clientHeight);
            renderOnce();
        });

        // ---------- LOOP ----------
        function animate() {
            requestAnimationFrame(animate);
            controls.update();
            renderer.render(scene, camera);
        }

        function renderOnce() {
            renderer.render(scene, camera);
        }
        animate();
    </script>
</body>

</html>
<?php /**PATH /home/plossayokesen/public_html/resources/views/lab/webgl.blade.php ENDPATH**/ ?>