From 64d9d695216a6c07bca47b6edcd59aea7634ddbd Mon Sep 17 00:00:00 2001 From: netpro2k <netpro2k@gmail.com> Date: Mon, 16 Jul 2018 17:55:38 -0700 Subject: [PATCH] Cleanup of media-loader --- src/components/media-loader.js | 62 ++++++++++++++++++++++ src/hub.js | 1 + src/utils/media-utils.js | 95 ++-------------------------------- 3 files changed, 66 insertions(+), 92 deletions(-) create mode 100644 src/components/media-loader.js diff --git a/src/components/media-loader.js b/src/components/media-loader.js new file mode 100644 index 000000000..1ee8e20a2 --- /dev/null +++ b/src/components/media-loader.js @@ -0,0 +1,62 @@ +import { getBox, getCenterAndHalfExtents, getScaleCoefficient } from "../utils/auto-box-collider"; +import { resolveFarsparkUrl } from "../utils/media-utils"; + +const fetchContentType = async url => fetch(url, { method: "HEAD" }).then(r => r.headers.get("content-type")); + +AFRAME.registerComponent("media-loader", { + schema: { + src: { type: "string" } + }, + + setShapeAndScale(didInflate) { + const mesh = this.el.getObject3D("mesh"); + const boxRoot = didInflate ? mesh.parent : mesh; + const box = getBox(this.el, boxRoot); + const scaleCoefficient = getScaleCoefficient(0.5, box); + if (this.el.body && this.el.body.shapes.length > 1) { + this.el.removeAttribute("shape"); + } else { + const center = new THREE.Vector3(); + const halfExtents = new THREE.Vector3(); + getCenterAndHalfExtents(this.el, box, center, halfExtents); + boxRoot.position.sub(center); + this.el.setAttribute("shape", { + shape: "box", + halfExtents: halfExtents + }); + } + const scale = this.el.object3D.scale; + this.el.setAttribute("scale", { + x: scale.x * scaleCoefficient, + y: scale.y * scaleCoefficient, + z: scale.z * scaleCoefficient + }); + }, + + // TODO: correctly handle case where src changes + async update() { + try { + const url = this.data.src; + + // show loading mesh + this.el.setObject3D("mesh", new THREE.Mesh(new THREE.BoxGeometry(), new THREE.MeshBasicMaterial())); + this.setShapeAndScale(); + + const { raw, origin, meta } = await resolveFarsparkUrl(url); + console.log("resolved", url, raw, origin, meta); + + const contentType = (meta && meta.expected_content_type) || (await fetchContentType(raw)); + if (contentType.startsWith("image/") || contentType.startsWith("video/")) { + this.el.setAttribute("image-plus", { src: raw, contentType }); + } else if (contentType.startsWith("model/gltf") || url.endsWith(".gltf") || url.endsWith(".glb")) { + this.el.addEventListener("model-loaded", evt => this.setShapeAndScale(evt.detail.didInflate), { once: true }); + this.el.setAttribute("gltf-model-plus", { src: raw, basePath: THREE.LoaderUtils.extractUrlBase(origin) }); + } else { + throw new Error(`Unsupported content type: ${contentType}`); + } + } catch (e) { + console.error("Error adding media", e); + this.el.setAttribute("image-plus", { src: "error" }); + } + } +}); diff --git a/src/hub.js b/src/hub.js index 674361330..65f541357 100644 --- a/src/hub.js +++ b/src/hub.js @@ -73,6 +73,7 @@ import "./components/auto-scale-cannon-physics-body"; import "./components/position-at-box-shape-border"; import "./components/remove-networked-object-button"; import "./components/destroy-at-extreme-distances"; +import "./components/media-loader"; import ReactDOM from "react-dom"; import React from "react"; diff --git a/src/utils/media-utils.js b/src/utils/media-utils.js index 5749035d5..5c0efb2ba 100644 --- a/src/utils/media-utils.js +++ b/src/utils/media-utils.js @@ -1,4 +1,3 @@ -import { getBox, getCenterAndHalfExtents, getScaleCoefficient } from "./auto-box-collider"; const whitelistedHosts = [/^.*\.reticulum\.io$/, /^.*hubs\.mozilla\.com$/, /^hubs\.local$/]; const isHostWhitelisted = hostname => !!whitelistedHosts.filter(r => r.test(hostname)).length; let resolveMediaUrl = "/api/v1/media"; @@ -18,108 +17,20 @@ export const resolveFarsparkUrl = async url => { }).then(r => r.json()); }; -const fetchContentType = async url => fetch(url, { method: "HEAD" }).then(r => r.headers.get("content-type")); - let interactableId = 0; const offset = { x: 0, y: 0, z: -1.5 }; -export const spawnNetworkedImage = (entity, src, contentType) => { - entity.id = "interactable-image-" + interactableId++; - // entity.setAttribute("networked", { template: "#interactable-image" }); - // entity.addEventListener("image-loaded", function onBodyLoaded() { - // entity.removeEventListener("image-loaded", onBodyLoaded); - // }); - entity.setAttribute("image-plus", { src, contentType }); - return entity; -}; - -export const spawnNetworkedInteractable = (entity, src, basePath) => { - entity.id = "interactable-model-" + interactableId++; - // entity.setAttribute("networked", { template: "#interactable-model" }); - entity.addEventListener("model-loaded", function onModelLoaded(evt) { - entity.removeEventListener("model-loaded", onModelLoaded); - setShapeAndScale(entity, evt.detail.didInflate); - }); - entity.setAttribute("gltf-model-plus", { src: src, basePath: basePath }); - return entity; -}; - -AFRAME.registerComponent("media-loader", { - schema: { - src: { type: "string" } - }, - - async update() { - const entity = this.el; - const url = this.data.src; - - try { - // show loading mesh - entity.setObject3D("mesh", new THREE.Mesh(new THREE.BoxGeometry(), new THREE.MeshBasicMaterial())); - setShapeAndScale(entity); - - const { raw, origin, meta } = await resolveFarsparkUrl(url); - console.log("resolved", url, raw, origin, meta); - - const contentType = (meta && meta.expected_content_type) || (await fetchContentType(raw)); - if (contentType.startsWith("image/") || contentType.startsWith("video/")) { - return spawnNetworkedImage(entity, raw, contentType); - } else if (contentType.startsWith("model/gltf") || url.endsWith(".gltf") || url.endsWith(".glb")) { - return spawnNetworkedInteractable(entity, raw, THREE.LoaderUtils.extractUrlBase(origin)); - } else { - throw new Error(`Unsupported content type: ${contentType}`); - } - } catch (e) { - console.error("Error adding media", e); - return spawnNetworkedImage(entity, "error"); - } - } -}); - -export const addMedia = url => { +export const addMedia = src => { const scene = AFRAME.scenes[0]; const entity = document.createElement("a-entity"); + entity.id = "interactable-media-" + interactableId++; entity.setAttribute("networked", { template: "#interactable-media" }); - // entity.setObject3D("mesh", new THREE.Mesh(new THREE.BoxGeometry(), new THREE.MeshBasicMaterial())); - // entity.classList.add("interactable"); - // entity.setAttribute("body", { type: "dynamic", shape: "none", mass: "1" }); - // entity.setAttribute("grabbable", ""); - // entity.setAttribute("hoverable", ""); - // entity.setAttribute("stretchable", { useWorldPosition: true, usePhysics: "never" }); - // entity.setAttribute("sticky-object", { autoLockOnRelease: true, autoLockOnLoad: true }); - // entity.setAttribute("destroy-at-extreme-distances", ""); + entity.setAttribute("media-loader", { src }); entity.setAttribute("offset-relative-to", { target: "#player-camera", offset: offset, selfDestruct: true }); - entity.setAttribute("media-loader", { src: url }); - // setShapeAndScale(entity); scene.appendChild(entity); return entity; }; - -function setShapeAndScale(entity, didInflate) { - const mesh = entity.getObject3D("mesh"); - const boxRoot = didInflate ? mesh.parent : mesh; - const box = getBox(entity, boxRoot); - const scaleCoefficient = getScaleCoefficient(0.5, box); - if (entity.components.body && entity.components.body.body && entity.components.body.body.shapes.length > 1) { - entity.removeAttribute("shape"); - } else { - const center = new THREE.Vector3(); - const halfExtents = new THREE.Vector3(); - getCenterAndHalfExtents(entity, box, center, halfExtents); - boxRoot.position.sub(center); - entity.setAttribute("shape", { - shape: "box", - halfExtents: halfExtents - }); - } - const scale = entity.object3D.scale; - entity.setAttribute("scale", { - x: scale.x * scaleCoefficient, - y: scale.y * scaleCoefficient, - z: scale.z * scaleCoefficient - }); -} -- GitLab