diff --git a/src/elements/a-gltf-entity.js b/src/components/gltf-model-plus.js similarity index 58% rename from src/elements/a-gltf-entity.js rename to src/components/gltf-model-plus.js index e88f7a76bf6ee4218f37997d9497e576b3bed55a..bcc9429adcac9b2bf5b76992d6def8f2a285c5bb 100644 --- a/src/elements/a-gltf-entity.js +++ b/src/components/gltf-model-plus.js @@ -187,133 +187,95 @@ function cachedLoadGLTF(src, onProgress) { }); } -AFRAME.registerElement("a-gltf-entity", { - prototype: Object.create(AFRAME.AEntity.prototype, { - load: { - async value() { - if (this.hasLoaded || !this.parentEl) { - return; - } - - // The code above and below this are from AEntity.prototype.load, we need to monkeypatch in gltf loading mid function - this.loadTemplates(); - await this.applySrc(this.getAttribute("src")); - // - - AFRAME.ANode.prototype.load.call(this, () => { - // Check if entity was detached while it was waiting to load. - if (!this.parentEl) { - return; - } +AFRAME.registerComponent("gltf-model-plus", { + schema: { + src: { type: "string" }, + inflate: { default: false } + }, - this.updateComponents(); - if (this.isScene || this.parentEl.isPlaying) { - this.play(); - } - }); - } - }, - - loadTemplates: { - value() { - this.templates = []; - this.querySelectorAll(":scope > template").forEach(templateEl => - this.templates.push({ - selector: templateEl.getAttribute("data-selector"), - templateRoot: document.importNode(templateEl.content.firstElementChild, true) - }) - ); - } - }, - - applySrc: { - async value(src) { - try { - // If the src attribute is a selector, get the url from the asset item. - if (src && src.charAt(0) === "#") { - const assetEl = document.getElementById(src.substring(1)); - - const fallbackSrc = assetEl.getAttribute("src"); - const highSrc = assetEl.getAttribute("high-src"); - const lowSrc = assetEl.getAttribute("low-src"); - - if (highSrc && window.APP.quality === "high") { - src = highSrc; - } else if (lowSrc && window.APP.quality === "low") { - src = lowSrc; - } else { - src = fallbackSrc; - } - } + init() { + this.loadTemplates(); + }, - if (src === this.lastSrc) return; - this.lastSrc = src; + update() { + this.applySrc(this.data.src); + }, - if (!src) { - if (this.inflatedEl) { - console.warn("gltf-entity set to an empty source, unloading inflated model."); - this.removeInflatedEl(); - } - return; - } + loadTemplates() { + this.templates = []; + this.el.querySelectorAll(":scope > template").forEach(templateEl => + this.templates.push({ + selector: templateEl.getAttribute("data-selector"), + templateRoot: document.importNode(templateEl.content.firstElementChild, true) + }) + ); + }, - const model = await cachedLoadGLTF(src); + async applySrc(src) { + try { + // If the src attribute is a selector, get the url from the asset item. + if (src && src.charAt(0) === "#") { + const assetEl = document.getElementById(src.substring(1)); + + const fallbackSrc = assetEl.getAttribute("src"); + const highSrc = assetEl.getAttribute("high-src"); + const lowSrc = assetEl.getAttribute("low-src"); + + if (highSrc && window.APP.quality === "high") { + src = highSrc; + } else if (lowSrc && window.APP.quality === "low") { + src = lowSrc; + } else { + src = fallbackSrc; + } + } - // If we started loading something else already - // TODO: there should be a way to cancel loading instead - if (src != this.lastSrc) return; + if (src === this.lastSrc) return; + this.lastSrc = src; - // If we had inflated something already before, clean that up + if (!src) { + if (this.inflatedEl) { + console.warn("gltf-model-plus set to an empty source, unloading inflated model."); this.removeInflatedEl(); + } + return; + } - this.model = model.scene || model.scenes[0]; - this.model.animations = model.animations; + const model = await cachedLoadGLTF(src); - this.setObject3D("mesh", this.model); + // If we started loading something else already + // TODO: there should be a way to cancel loading instead + if (src != this.lastSrc) return; - if (this.getAttribute("inflate")) { - this.inflatedEl = inflateEntities(this, this.model); - // TODO: Still don't fully understand the lifecycle here and how it differs between browsers, we should dig in more - // Wait one tick for the appended custom elements to be connected before attaching templates - await nextTick(); - if (src != this.lastSrc) return; // TODO: there must be a nicer pattern for this - this.templates.forEach(attachTemplate.bind(null, this)); - } + // If we had inflated something already before, clean that up + this.removeInflatedEl(); - this.emit("model-loaded", { format: "gltf", model: this.model }); - } catch (e) { - const message = (e && e.message) || "Failed to load glTF model"; - console.error(message); - this.emit("model-error", { format: "gltf", src }); - } - } - }, + this.model = model.scene || model.scenes[0]; + this.model.animations = model.animations; - removeInflatedEl: { - value() { - if (this.inflatedEl) { - this.inflatedEl.parentNode.removeChild(this.inflatedEl); - delete this.inflatedEl; - } - } - }, + this.el.setObject3D("mesh", this.model); - attributeChangedCallback: { - value(attr, oldVal, newVal) { - if (attr === "src") { - this.applySrc(newVal); - } - AFRAME.AEntity.prototype.attributeChangedCallback.call(this, attr, oldVal, newVal); + if (this.data.inflate) { + this.inflatedEl = inflateEntities(this.el, this.model); + // TODO: Still don't fully understand the lifecycle here and how it differs between browsers, we should dig in more + // Wait one tick for the appended custom elements to be connected before attaching templates + await nextTick(); + if (src != this.lastSrc) return; // TODO: there must be a nicer pattern for this + this.templates.forEach(attachTemplate.bind(null, this.el)); } - }, - setAttribute: { - value(attr, arg1, arg2) { - if (attr === "src") { - this.applySrc(arg1); - } - AFRAME.AEntity.prototype.setAttribute.call(this, attr, arg1, arg2); - } + this.el.emit("model-loaded", { format: "gltf", model: this.model }); + } catch (e) { + const message = (e && e.message) || "Failed to load glTF model"; + console.error(message); + this.el.emit("model-error", { format: "gltf", src }); } - }) + }, + + removeInflatedEl() { + if (this.inflatedEl) { + this.inflatedEl.parentNode.removeChild(this.inflatedEl); + delete this.inflatedEl; + } + } }); diff --git a/src/components/player-info.js b/src/components/player-info.js index 8cb265a67b9c67ac26510d6b8a03efb59703c931..57d459862a843bd9dd78e65071e2cb3f62b19dab 100644 --- a/src/components/player-info.js +++ b/src/components/player-info.js @@ -25,7 +25,7 @@ AFRAME.registerComponent("player-info", { const modelEl = this.el.querySelector(".model"); if (this.data.avatar && modelEl) { - modelEl.setAttribute("src", this.data.avatar); + modelEl.setAttribute("gltf-model-plus", "src", this.data.avatar); } } }); diff --git a/src/gltf-component-mappings.js b/src/gltf-component-mappings.js index e4cf086733ad1e0dc547abafe3fb37ed025a5608..bde7f06975d11cf32b0626466bb03f2ce649c526 100644 --- a/src/gltf-component-mappings.js +++ b/src/gltf-component-mappings.js @@ -1,4 +1,4 @@ -import "./elements/a-gltf-entity"; +import "./components/gltf-model-plus"; AFRAME.AGLTFEntity.registerComponent("scale-audio-feedback", "scale-audio-feedback"); AFRAME.AGLTFEntity.registerComponent("loop-animation", "loop-animation"); diff --git a/src/room.html b/src/room.html index 132e6af23c42d61553fc1c78c43ff0afc0cf188b..d4e915a77250ad81c5e1e15390de19c83c4f5b3c 100644 --- a/src/room.html +++ b/src/room.html @@ -60,7 +60,7 @@ <a-entity class="right-controller"></a-entity> - <a-gltf-entity class="model" inflate="true"> + <a-entity class="model" gltf-model-plus="inflate: true"> <template data-selector=".RootScene"> <a-entity ik-controller animation-mixer></a-entity> </template> @@ -93,13 +93,13 @@ <template data-selector=".RightHand"> <a-entity personal-space-invader ></a-entity> </template> - </a-gltf-entity> + </a-entity> </a-entity> </template> <template id="interactable-template"> <a-entity - gltf-model="#interactable-duck" + gltf-model-plus="src: #interactable-duck" scale="2 2 2" class="interactable" super-networked-interactable="counter: #counter; mass: 5;" @@ -125,7 +125,7 @@ <a-entity id="counter" networked-counter="max: 3; ttl: 120"></a-entity> <a-entity - gltf-model="#interactable-duck" + gltf-model-plus="src: #interactable-duck" scale="2 2 2" class="interactable" super-spawner="template: #interactable-template;" @@ -212,7 +212,7 @@ app-mode-toggle-attribute__line="mode: hud; property: visible;" ></a-entity> - <a-gltf-entity class="model" inflate="true"> + <a-entity gltf-model-plus="inflate: true;" class="model"> <template data-selector=".RootScene"> <a-entity ik-controller @@ -233,14 +233,14 @@ <template data-selector=".LeftHand"> <a-entity> - <a-gltf-entity + <a-entity id="watch" - src="#watch-model" + gltf-model-plus="src: #watch-model" bone-mute-state-indicator scale="1.5 1.5 1.5" rotation="0 -90 90" position="0 -0.04 0" - ></a-gltf-entity> + ></a--entity> <a-entity event-repeater="events: action_grab, action_release; eventSource: #player-left-controller" static-body="shape: sphere; sphereRadius: 0.02" @@ -261,7 +261,7 @@ </a-entity> </template> - </a-gltf-entity> + </a-entity> </a-entity> <!-- Lights --> @@ -272,34 +272,34 @@ ></a-entity> <!-- Environment --> - <a-gltf-entity + <a-entity id="meeting-space" - src="#meeting-space1-mesh" + gltf-model-plus="src: #meeting-space1-mesh" position="0 0 0" - ></a-gltf-entity> + ></a-entity> - <a-gltf-entity + <a-entity id="outdoor-facade" - src="#outdoor-facade-mesh" + gltf-model-plus="src: #outdoor-facade-mesh" position="0 0 0" xr="ar: false" - ></a-gltf-entity> + ></a-ntity> - <a-gltf-entity + <a-entity id="floor-nav" - src="#floor-nav-mesh" + gltf-model-plus="src: #floor-nav-mesh" visible="false" position="0 0 0" xr="ar: false" - ></a-gltf-entity> + ></a-entity> - <a-gltf-entity + <a-entity id="cliff-vista" - src="#cliff-vista-mesh" + gltf-model-plus="src: #cliff-vista-mesh" layers="reflection:true" position="0 0 0" xr="ar: false" - ></a-gltf-entity> + ></a-entity> <a-entity id="skybox" id="skybox" diff --git a/src/room.js b/src/room.js index 909e8977f7bd4ce6d30e6ce4ddfc183a7e685c3b..739aa6258c3cc6188803ef1ebc8d58af4d4328e6 100644 --- a/src/room.js +++ b/src/room.js @@ -41,6 +41,7 @@ import "./components/player-info"; import "./components/debug"; import "./components/animation-mixer"; import "./components/loop-animation"; +import "./components/gltf-model-plus"; import ReactDOM from "react-dom"; import React from "react"; @@ -49,8 +50,6 @@ import UIRoot from "./react-components/ui-root"; import "./systems/personal-space-bubble"; import "./systems/app-mode"; -import "./elements/a-gltf-entity"; - import "./gltf-component-mappings"; import { App } from "./App"; @@ -176,8 +175,7 @@ async function enterScene(mediaStream, enterInVR) { for (const track of videoTracks) { mediaStream.addTrack(track); } - } - else { + } else { for (const track of mediaStream.getVideoTracks()) { mediaStream.removeTrack(track); }