From c47d7126243e815edf6d2ae3e66bd54ea8ef7da1 Mon Sep 17 00:00:00 2001 From: eater <=@eater.me> Date: Sun, 1 Mar 2020 14:22:51 +0100 Subject: [PATCH] scale down, add hash, allow vampires, add mobile fixes --- public/index.html | 22 ++++++++++-- src/HeadRenderer.js | 4 +-- src/Shape.js | 4 +-- src/ShapeCollection.js | 4 ++- src/index.js | 77 ++++++++++++++++++++++++++++++++---------- 5 files changed, 86 insertions(+), 25 deletions(-) diff --git a/public/index.html b/public/index.html index c85a323..f32da9e 100644 --- a/public/index.html +++ b/public/index.html @@ -18,13 +18,29 @@ .wizard { position: absolute; - padding: 25px; - width: 100%; - bottom: 0; + width: calc(100% - 50px); + left: 25px; + bottom: 25px; display: flex; flex-direction: column; align-items: center; justify-content: center; + background: rgba(255, 255, 255, 0.2); + } + + @media (max-width:600px) { + body { + font-size: 1.3em; + } + + input, select { + font-size: 1em; + } + + button { + width: 5em; + height: 3em; + } } diff --git a/src/HeadRenderer.js b/src/HeadRenderer.js index 904f7e5..3365ad2 100644 --- a/src/HeadRenderer.js +++ b/src/HeadRenderer.js @@ -17,8 +17,8 @@ export class HeadRenderer { this.renderer.setSize(W, H); document.body.appendChild(this.renderer.domElement); - this.camera = new THREE.PerspectiveCamera(70, W / H, 1, 2000); - this.camera.position.z = 600; + this.camera = new THREE.PerspectiveCamera(70, W / H, 1, 200); + this.camera.position.z = 60; this.scene = new THREE.Scene(); this.scene.background = new Color(0xffffff); diff --git a/src/Shape.js b/src/Shape.js index df4498b..0e5a1c8 100644 --- a/src/Shape.js +++ b/src/Shape.js @@ -48,7 +48,7 @@ export class Shape { const params = { color: 0xffffff, transparent: true, - alphaTest: 0.5, + alphaTest: 0.2, }; if (this.textureInfo) { let Loader; @@ -129,7 +129,7 @@ export class Shape { geometry.translate(this.translation[0], this.translation[1], this.translation[2]); // Scale up a bit - geometry.scale(20, 20, 20); + geometry.scale(2, 2, 2); // Rotate the face so it faces us \o/ geometry.rotateX(290 * (Math.PI / 180)); diff --git a/src/ShapeCollection.js b/src/ShapeCollection.js index b3fbac9..83a959e 100644 --- a/src/ShapeCollection.js +++ b/src/ShapeCollection.js @@ -23,4 +23,6 @@ export class ShapeCollection { return this.group } -} \ No newline at end of file +} + +window.ShapeCollection = ShapeCollection; \ No newline at end of file diff --git a/src/index.js b/src/index.js index d5d6f3f..9ecc01a 100644 --- a/src/index.js +++ b/src/index.js @@ -25,7 +25,8 @@ window.addEventListener("load", async () => { part1.innerHTML = ""; part2.innerHTML = ""; - const indexed = {}; + const indexed = window.indexed = {}; + const byName = window.byName = {}; const tree = {}; const shapeCache = {}; @@ -33,30 +34,22 @@ window.addEventListener("load", async () => { headRenderer.expose(); for (let mesh of allMeshes) { - let [_, x, race, gender, part, nr = undefined] = mesh.name.split('_'); + let [_, __, race, gender, part, nr = undefined] = mesh.name.split('_'); race = race.replace(new RegExp("\\s+"), ' '); - if (race.toLowerCase() === "khajiit") { - console.log(part, mesh.name, nr); - } - if (x !== 'N') { - continue; + if (race === 'DarkElf') { + race = 'Dark Elf' } - if (nr === undefined) { + if (nr === undefined && !['head', 'hair'].includes(part.toLowerCase())) { [_, part, nr] = part.match(/(head|hair)(\d+)?/i) || []; - console.log(part); - - if (!nr) { - continue; - } } let option = document.createElement("option"); option.textContent = mesh.name; option.value = mesh.id = uuidv4(); indexed[mesh.id] = mesh; - + byName[mesh.name] = mesh.id; if (mesh.name.toLowerCase().indexOf("hair") !== -1) { part1.appendChild(option); @@ -89,7 +82,7 @@ window.addEventListener("load", async () => { setRace(race.value); }); - function setRace(name) { + function setRace(name, propagate = true) { race.value = name; gender.innerHTML = ""; for (let genderX in tree[name]) { @@ -99,7 +92,9 @@ window.addEventListener("load", async () => { gender.appendChild(option); } - setGender(gender.value) + if (propagate) { + setGender(gender.value) + } } gender.addEventListener("change", () => { @@ -112,19 +107,66 @@ window.addEventListener("load", async () => { setHead(tree[race.value][name]['head'][0]); } - setRace("Dark Elf"); + // Collect hash query before setting defaults + let q = collectHashQuery(); + + // Dark Elf / M is what Morrowind starts you with + setRace("Dark Elf", false); setGender("M"); + updateFromHash(q); + + function collectHashQuery() { + return location.hash.substr(1).split('&').reduce((c, x) => { + let [name, value = ""] = x.split('=', 2).map(y => decodeURIComponent(y)); + c[name] = value; + return c; + }, {}); + } + + function updateFromHash(q) { + if (!q) { + q = collectHashQuery(); + } + + if (byName[q['head']] && q['head'].toLowerCase().includes('head')) { + setHead(byName[q['head']]); + } else { + if (q['head']) { + console.log("No head found with name: ", q['head']); + } + } + + if (byName[q['hair']] && q['hair'].toLowerCase().includes('hair')) { + setHair(byName[q['hair']]); + } else { + if (q['hair']) { + console.log("No hair found with name: ", q['hair']); + } + } + } + + updateFromHash(); + + window.addEventListener('hashchange', () => { + updateFromHash(); + }); + function getShape(name) { return new ShapeCollection(indexed[name], "blob/textures/"); } + function updateHash() { + location.hash = `head=${encodeURIComponent(indexed[part2.value].name)}&hair=${encodeURIComponent(indexed[part1.value].name)}`; + } + function setHair(id) { part1.value = id; if (shape1 !== null) { headRenderer.remove(shape1); } headRenderer.add(shape1 = getShape(id)); + updateHash(); } part1.addEventListener("change", () => { @@ -147,6 +189,7 @@ window.addEventListener("load", async () => { headRenderer.remove(shape2); } headRenderer.add(shape2 = getShape(id)); + updateHash(); } part2.addEventListener("change", () => {