diff --git a/src/load-media-on-paste-or-drop.ts b/src/load-media-on-paste-or-drop.ts index 90ed87b0d0..fbef04273f 100644 --- a/src/load-media-on-paste-or-drop.ts +++ b/src/load-media-on-paste-or-drop.ts @@ -15,7 +15,7 @@ type UploadResponse = { origin: string; }; -function spawnFromUrl(text: string) { +export function spawnFromUrl(text: string) { if (!text) { return; } @@ -36,7 +36,7 @@ function spawnFromUrl(text: string) { obj.lookAt(avatarPov.getWorldPosition(new Vector3())); } -async function spawnFromFileList(files: FileList) { +export async function spawnFromFileList(files: FileList) { for (const file of files) { const desiredContentType = file.type || guessContentType(file.name); const params = await upload(file, desiredContentType) @@ -94,10 +94,21 @@ async function onPaste(e: ClipboardEvent) { spawnFromUrl(text); } +let lastDebugScene: string; function onDrop(e: DragEvent) { if (!(AFRAME as any).scenes[0].is("entered")) { return; } + + if (qsTruthy("debugLocalScene")) { + URL.revokeObjectURL(lastDebugScene); + if (!e.dataTransfer?.files.length) return; + const url = URL.createObjectURL(e.dataTransfer.files[0]); + APP.hubChannel!.updateScene(url); + lastDebugScene = url; + return; + } + const files = e.dataTransfer?.files; if (files && files.length) { e.preventDefault(); diff --git a/src/scene-entry-manager.js b/src/scene-entry-manager.js index 7df692fd54..fbbef42db7 100644 --- a/src/scene-entry-manager.js +++ b/src/scene-entry-manager.js @@ -26,6 +26,9 @@ import { addComponent, removeEntity } from "bitecs"; import { MyCameraTool } from "./bit-components"; import { anyEntityWith } from "./utils/bit-utils"; import { moveToSpawnPoint } from "./bit-systems/waypoint"; +import { spawnFromFileList, spawnFromUrl } from "./load-media-on-paste-or-drop"; + +const useNewLoader = qsTruthy("newLoader"); export default class SceneEntryManager { constructor(hubChannel, authChannel, history) { @@ -76,7 +79,7 @@ export default class SceneEntryManager { await exit2DInterstitialAndEnterVR(true); } - if (qsTruthy("newLoader")) { + if (useNewLoader) { moveToSpawnPoint(APP.world, this.scene.systems["hubs-systems"].characterController); } else { const waypointSystem = this.scene.systems["hubs-systems"].waypointSystem; @@ -215,9 +218,26 @@ export default class SceneEntryManager { }; _setupMedia = () => { - const offset = { x: 0, y: 0, z: -1.5 }; const spawnMediaInfrontOfPlayer = (src, contentOrigin) => { + console.warn( + "Spawning newLoader object using `spawnMediaInFrontOfPlayer`. This codepath should likely be made more direct.", + src, + contentOrigin + ); + if (useNewLoader) { + if (typeof src === "string") { + spawnFromUrl(src); + } else { + spawnFromFileList([src]); + } + } else { + spawnMediaInfrontOfPlayerAndReturn(src, contentOrigin).eid; + } + }; + // HACK we only care about the return value in 1 spot, don't want to deal with that in the newLoader path + const spawnMediaInfrontOfPlayerAndReturn = (src, contentOrigin) => { if (!this.hubChannel.can("spawn_and_move_media")) return; + const offset = { x: 0, y: 0, z: -1.5 }; const { entity, orientation } = addMedia( src, "#interactable-media", @@ -270,7 +290,7 @@ export default class SceneEntryManager { this.scene.addEventListener("action_vr_notice_closed", () => forceExitFrom2DInterstitial()); - if (!qsTruthy("newLoader")) { + if (!useNewLoader) { document.addEventListener("paste", e => { if ( (e.target.matches("input, textarea") || e.target.contentEditable === "true") && @@ -340,7 +360,7 @@ export default class SceneEntryManager { if (target === "avatar") { this.avatarRig.setAttribute("player-info", { isSharingAvatarCamera: true }); } else { - currentVideoShareEntity = spawnMediaInfrontOfPlayer(this.mediaDevicesManager.mediaStream, undefined); + currentVideoShareEntity = spawnMediaInfrontOfPlayerAndReturn(this.mediaDevicesManager.mediaStream, undefined); // Wire up custom removal event which will stop the stream. currentVideoShareEntity.setAttribute( "emit-scene-event-on-remove", diff --git a/src/utils/load-image.tsx b/src/utils/load-image.tsx index b19a560a62..d2d4bccd65 100644 --- a/src/utils/load-image.tsx +++ b/src/utils/load-image.tsx @@ -7,9 +7,22 @@ import { HubsWorld } from "../app"; import { Texture } from "three"; import { AlphaMode } from "./create-image-mesh"; +// TODO AlphaMode is written in JS and should be a ts enum +type AlphaModeType = typeof AlphaMode.Opaque | typeof AlphaMode.Mask | typeof AlphaMode.Blend; export function* loadImage(world: HubsWorld, url: string, contentType: string) { const { texture, ratio, cacheKey }: { texture: Texture; ratio: number; cacheKey: string } = yield loadTextureCancellable(url, 1, contentType); + + // TODO it would be nice if we could be less agressive with transparency here. + // Doing so requires inspecting the raw file data upstream of here and passing + // that info through somehow which feels tricky. + let alphaMode: AlphaModeType = AlphaMode.Blend; + if (contentType === "image/gif") { + alphaMode = AlphaMode.Mask; + } else if (contentType === "image/jpeg") { + alphaMode = AlphaMode.Opaque; + } + return renderAsEntity( world,