From bde46f689bde6c05c5ecc2047d4f5e6866df6a49 Mon Sep 17 00:00:00 2001
From: netpro2k <netpro2k@gmail.com>
Date: Wed, 14 Mar 2018 18:19:51 -0700
Subject: [PATCH] Add support for changing src on an a-gltf-entity, also some
 code cleanup

---
 src/components/debug.js       |  25 +++++
 src/elements/a-gltf-entity.js | 169 ++++++++++++++++++++--------------
 src/room.js                   |   1 +
 3 files changed, 127 insertions(+), 68 deletions(-)
 create mode 100644 src/components/debug.js

diff --git a/src/components/debug.js b/src/components/debug.js
new file mode 100644
index 000000000..77202f032
--- /dev/null
+++ b/src/components/debug.js
@@ -0,0 +1,25 @@
+AFRAME.registerComponent("lifecycle-checker", {
+  schema: {
+    tick: { default: false }
+  },
+  init: function() {
+    console.log("init", this.el);
+  },
+  update: function() {
+    console.log("update", this.el);
+  },
+  tick: function() {
+    if (this.data.tick) {
+      console.log("tick", this.el);
+    }
+  },
+  remove: function() {
+    console.log("remove", this.el);
+  },
+  pause: function() {
+    console.log("pause", this.el);
+  },
+  play: function() {
+    console.log("play", this.el);
+  }
+});
diff --git a/src/elements/a-gltf-entity.js b/src/elements/a-gltf-entity.js
index 8c274cb44..f1afe249b 100644
--- a/src/elements/a-gltf-entity.js
+++ b/src/elements/a-gltf-entity.js
@@ -70,7 +70,7 @@ function cloneGltf(gltf) {
   return clone;
 }
 
-const inflateEntities = function(classPrefix, parentEl, node) {
+const inflateEntities = function(parentEl, node) {
   // setObject3D mutates the node's parent, so we have to copy
   const children = node.children.slice(0);
 
@@ -78,7 +78,7 @@ const inflateEntities = function(classPrefix, parentEl, node) {
 
   // Remove invalid CSS class name characters.
   const className = (node.name || node.uuid).replace(/[^\w-]/g, "");
-  el.classList.add(classPrefix + className);
+  el.classList.add(className);
   parentEl.appendChild(el);
 
   // AFRAME rotation component expects rotations in YXZ, convert it
@@ -135,8 +135,10 @@ const inflateEntities = function(classPrefix, parentEl, node) {
   }
 
   children.forEach(childNode => {
-    inflateEntities(classPrefix, el, childNode);
+    inflateEntities( el, childNode);
   });
+
+  return el;
 };
 
 function attachTemplate(templateEl) {
@@ -158,93 +160,124 @@ function attachTemplate(templateEl) {
   }
 }
 
+function cachedLoadGLTF(src, onProgress) {
+  return new Promise((resolve, reject) => {
+    // Load the gltf model from the cache if it exists.
+    if (GLTFCache[src]) {
+      // Use a cloned copy of the cached model.
+      resolve(cloneGltf(GLTFCache[src]));
+    } else {
+      // Otherwise load the new gltf model.
+      new THREE.GLTFLoader().load(
+        src,
+        model => {
+          if (!GLTFCache[src]) {
+            // Store a cloned copy of the gltf model.
+            GLTFCache[src] = cloneGltf(model);
+          }
+          resolve(model);
+        },
+        onProgress,
+        reject
+      );
+    }
+  });
+}
+
 AFRAME.registerElement("a-gltf-entity", {
   prototype: Object.create(AFRAME.AEntity.prototype, {
     load: {
-      value() {
+      async value() {
         if (this.hasLoaded || !this.parentEl) {
           return;
         }
 
-        // Get the src url.
-        let src = this.getAttribute("src");
-
-        // If the src attribute is a selector, get the url from the asset item.
-        if (src.charAt(0) === "#") {
-          const assetEl = document.getElementById(src.substring(1));
+        // The code above and below this are from AEntity.prototype.load, we need to monkeypatch in gltf loading mid function
+        await this.setSrc(this.getAttribute("src"));
 
-          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;
+        AFRAME.ANode.prototype.load.call(this, () => {
+          // Check if entity was detached while it was waiting to load.
+          if (!this.parentEl) {
+            return;
           }
-        }
 
-        const onLoad = gltfModel => {
-          if (!GLTFCache[src]) {
-            // Store a cloned copy of the gltf model.
-            GLTFCache[src] = cloneGltf(gltfModel);
+          this.updateComponents();
+          if (this.isScene || this.parentEl.isPlaying) {
+            this.play();
+          }
+        });
+      }
+    },
+
+    setSrc: {
+      async value(src) {
+        try {
+          // If the src attribute is a selector, get the url from the asset item.
+          if (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;
+            }
           }
 
-          this.model = gltfModel.scene || gltfModel.scenes[0];
-          this.model.animations = gltfModel.animations;
-
-          this.setObject3D("mesh", this.model);
-          this.emit("model-loaded", { format: "gltf", model: this.model });
+          if (src === this.lastSrc) return;
+          this.lastSrc = src;
 
-          if (this.getAttribute("inflate")) {
-            inflate(this.model, finalizeLoad);
-          } else {
-            finalizeLoad();
-          }
-        };
+          const model = await cachedLoadGLTF(src);
 
-        const inflate = (model, callback) => {
-          inflateEntities("", this, model);
-          this.querySelectorAll(":scope > template").forEach(attachTemplate);
+          // If we started loading something else already
+          // TODO: there should be a way to cancel loading instead
+          if (src != this.lastSrc) return;
 
-          // Wait one tick for the appended custom elements to be connected before calling finalizeLoad
-          setTimeout(callback, 0);
-        };
+          // If we had inflated something already before, clean that up
+          if (this.inflatedEl) {
+            this.inflatedEl.parentNode.removeChild(this.inflatedEl);
+            delete this.inflatedEl;
+          }
 
-        const finalizeLoad = () => {
-          AFRAME.ANode.prototype.load.call(this, () => {
-            // Check if entity was detached while it was waiting to load.
-            if (!this.parentEl) {
-              return;
-            }
+          this.model = model.scene || model.scenes[0];
+          this.model.animations = model.animations;
 
-            this.updateComponents();
-            if (this.isScene || this.parentEl.isPlaying) {
-              this.play();
-            }
-          });
-        };
+          this.setObject3D("mesh", this.model);
 
-        // Load the gltf model from the cache if it exists.
-        const gltf = GLTFCache[src];
+          if (this.getAttribute("inflate")) {
+            this.inflatedEl = inflateEntities(this, this.model);
+            this.querySelectorAll(":scope > template").forEach(attachTemplate);
+          }
 
-        if (gltf) {
-          // Use a cloned copy of the cached model.
-          const clonedGltf = cloneGltf(gltf);
-          onLoad(clonedGltf);
-          return;
+          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 });
         }
+      }
+    },
 
-        // Otherwise load the new gltf model.
-        new THREE.GLTFLoader().load(src, onLoad, undefined /* onProgress */, error => {
-          // On glTF load error
+    attributeChangedCallback: {
+      value(attr, oldVal, newVal) {
+        if (attr === "src") {
+          this.setSrc(newVal);
+        }
+        AFRAME.AEntity.prototype.attributeChangedCallback.call(this, attr, oldVal, newVal);
+      }
+    },
 
-          const message = error && error.message ? error.message : "Failed to load glTF model";
-          console.warn(message);
-          this.emit("model-error", { format: "gltf", src });
-        });
+    setAttribute: {
+      value(attr, arg1, arg2) {
+        if (attr === "src") {
+          this.setSrc(arg1);
+        }
+        AFRAME.AEntity.prototype.setAttribute.call(this, attr, arg1, arg2);
       }
     }
   })
diff --git a/src/room.js b/src/room.js
index 5af49f9b9..849cd012c 100644
--- a/src/room.js
+++ b/src/room.js
@@ -40,6 +40,7 @@ import "./components/layers";
 import "./components/spawn-controller";
 import "./components/animated-robot-hands";
 import "./components/hide-when-quality";
+import "./components/debug";
 
 import "./systems/personal-space-bubble";
 
-- 
GitLab