<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=0.5" />
<title>Mesh Viewer based on three.js</title>
<style>
body { margin: 0; }
</style>
<!--https://threejs.org/docs/index.html#manual/en/introduction/Installation-->
<script type="importmap">
  {
    "imports": {
      "three": "/.cdn/three/0.164.0/build/three.module.min.js",
      "three/addons/": "/.cdn/three/0.164.0/examples/jsm/"
    }
  }
</script>
</head>
<body>
<!--https://threejs.org/docs/index.html#manual/en/introduction/Creating-a-scene-->
<!--https://threejs.org/docs/index.html#examples/en/loaders/OBJLoader-->
<script type="module">
import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
import { OBJLoader } from 'three/addons/loaders/OBJLoader.js';
import { STLLoader } from 'three/addons/loaders/STLLoader.js';
import { GUI } from 'three/addons/libs/lil-gui.module.min.js';

const scene = new THREE.Scene();
scene.background = new THREE.Color(1,1,1);
scene.add(new THREE.AxesHelper(10));

if (window.matchMedia) {
  if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
    scene.background.set(0,0,0);
  }
}

const gui = new GUI();
gui.addColor(scene, 'background');

const camera = new THREE.PerspectiveCamera(
  60,
  window.innerWidth / window.innerHeight,
  0.1,
  1000
);
camera.position.set(100, -100, 100);
camera.up.set(0, 0, 1);
const light = new THREE.PointLight();
camera.add(light);
scene.add(camera);

// https://discourse.threejs.org/t/updates-to-lighting-in-three-js-r155/53733
const renderer = new THREE.WebGLRenderer();
renderer.useLegacyLights = true;
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;

function addOptions(folder, obj, material) {
  folder.add(obj, 'visible');
  folder.addColor(material, 'color');
  folder.add(material, 'wireframe');
}

function loadOBJ(filename) {
  const basename = filename.substring(filename.lastIndexOf('/') + 1);
  const folder = gui.addFolder(basename);
  const objloader = new OBJLoader();
  objloader.load(
    filename,
    function (obj) {
      const material = new THREE.MeshStandardMaterial();
      material.color = new THREE.Color(0.5, 0.5, 0.5);
      obj.traverse(
        function (child) {
          if (child instanceof THREE.Mesh) {
            child.material = material;
          }
        }
      );
      scene.add(obj);
      addOptions(folder, obj, material);
    }
  );
}

function loadSTL(filename) {
  const basename = filename.substring(filename.lastIndexOf('/') + 1);
  const folder = gui.addFolder(basename);
  const stlloader = new STLLoader();
  stlloader.load(
    filename,
    function (geometry) {
      const material = new THREE.MeshStandardMaterial();
      material.color = new THREE.Color(0.5, 0.5, 0.5);
      const mesh = new THREE.Mesh(geometry, material);
      scene.add(mesh);
      addOptions(folder, mesh, material);
    }
  );
}

function loadMesh(filename) {
  if (filename.endsWith('.obj')) {
    loadOBJ(filename);
  } else if (filename.endsWith('.stl')) {
    loadSTL(filename);
  }
}

function createCube() {
  const folder = gui.addFolder('Cube');
  const geometry = new THREE.BoxGeometry(10, 10, 10);
  const material = new THREE.MeshStandardMaterial();
  material.color = new THREE.Color(0.5, 0.5, 0.5);
  const mesh = new THREE.Mesh(geometry, material);
  scene.add(mesh);
  addOptions(folder, mesh, material);
}

const params = new URLSearchParams(window.location.search);
if (params.has('filename')) {
  loadMesh(params.get('filename'));
} else if (params.has('filenames[]')) {
  const filenames = params.getAll('filenames[]');
  if (Array.isArray(filenames) && filenames.length) {
    for (let i = 0; i < filenames.length; i++) {
      loadMesh(filenames[i]);
    }
  }
} else {
  createCube();
}

function onWindowResize() {
  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();
  renderer.setSize(window.innerWidth, window.innerHeight);
  renderer.render(scene, camera);
}
window.addEventListener('resize', onWindowResize);

function animate() {
  requestAnimationFrame(animate);
  controls.update();
  renderer.render(scene, camera);
}
animate();
</script>
</body>
</html>