Skip to content

Commit

Permalink
Clean up
Browse files Browse the repository at this point in the history
* Treat MediaImage/VideoLoaderData as part of MediaLoader
  component data. Less problematic because their life cycles
  will be synched with MediaLoader component.
* Remove dependency with entity and MediaImage/VideoLoaderData
  from loaders in src/utils. The loaders will be simpler.
  • Loading branch information
takahirox committed Aug 12, 2023
1 parent 81229b6 commit 7dc5aed
Showing 6 changed files with 158 additions and 82 deletions.
23 changes: 15 additions & 8 deletions src/bit-components.js
Original file line number Diff line number Diff line change
@@ -161,6 +161,21 @@ export const MediaContentBounds = defineComponent({
bounds: [Types.f32, 3]
});

// MediaImageLoaderData and MediaVideoLoaderData are
// for parameters set via glTF inflators
// inflateImageLoader and inflateVideoLoader.
// They are handled as part of MediaLoader component data.

/**
* @type {Map<EntityId, ImageLoaderParams}>}
*/
export const MediaImageLoaderData = new Map();

/**
* @type {Map<EntityId, VideoLoaderParams}>}
*/
export const MediaVideoLoaderData = new Map();

export const SceneRoot = defineComponent();
export const NavMesh = defineComponent();
export const SceneLoader = defineComponent({ src: Types.ui32 });
@@ -175,10 +190,6 @@ export const MediaImage = defineComponent({
MediaImage.cacheKey[$isStringType] = true;
MediaImage.projection[$isStringType] = true;
MediaImage.alphaMode[$isStringType] = true;
/**
* @type {Map<EntityId, ImageLoaderParams}>}
*/
export const MediaImageLoaderData = new Map();

export const NetworkedPDF = defineComponent({
pageNumber: Types.ui8
@@ -194,10 +205,6 @@ export const MediaVideo = defineComponent({
projection: Types.ui8
});
MediaVideo.projection[$isStringType] = true;
/**
* @type {Map<EntityId, VideoLoaderParams}>}
*/
export const MediaVideoLoaderData = new Map();
/**
* @type {Map<EntityId, HTMLVideoElement}>}
*/
96 changes: 63 additions & 33 deletions src/bit-systems/media-loading.ts
Original file line number Diff line number Diff line change
@@ -4,8 +4,10 @@ import { HubsWorld } from "../app";
import {
GLTFModel,
MediaContentBounds,
MediaImageLoaderData,
MediaLoaded,
MediaLoader,
MediaVideoLoaderData,
Networked,
ObjectMenuTarget
} from "../bit-components";
@@ -65,34 +67,6 @@ export function* waitForMediaLoaded(world: HubsWorld, eid: EntityID) {
}
}

// prettier-ignore
const loaderForMediaType = {
[MediaType.IMAGE]: (
world: HubsWorld,
eid: EntityID,
{ accessibleUrl, contentType }: { accessibleUrl: string, contentType: string }
) => loadImage(world, eid, accessibleUrl, contentType),
[MediaType.VIDEO]: (
world: HubsWorld,
eid: EntityID,
{ accessibleUrl, contentType }: { accessibleUrl: string, contentType: string }
) => loadVideo(world, eid, accessibleUrl, contentType),
[MediaType.MODEL]: (
world: HubsWorld,
eid: EntityID,
{ accessibleUrl, contentType }: { accessibleUrl: string, contentType: string }
) => loadModel(world, accessibleUrl, contentType, true),
[MediaType.PDF]: (world: HubsWorld, eid: EntityID, { accessibleUrl }: { accessibleUrl: string }) =>
loadPDF(world, accessibleUrl),
[MediaType.AUDIO]: (world: HubsWorld, eid: EntityID, { accessibleUrl }: { accessibleUrl: string }) =>
loadAudio(world, eid, accessibleUrl),
[MediaType.HTML]: (
world: HubsWorld,
eid: EntityID,
{ canonicalUrl, thumbnail }: { canonicalUrl: string, thumbnail: string }
) => loadHtml(world, canonicalUrl, thumbnail)
};

export const MEDIA_LOADER_FLAGS = {
RECENTER: 1 << 0,
RESIZE: 1 << 1,
@@ -189,6 +163,58 @@ type MediaInfo = {
thumbnail: string;
};

function* loadByMediaType(
world: HubsWorld,
eid: EntityID,
{
accessibleUrl,
canonicalUrl,
contentType,
mediaType,
thumbnail
}: MediaInfo
) {
// Note: For Image, Video, and Audio, parameters can be set via
// glTF image/video/audio inflators inflateImageLoader and
// inflateVideoLoader.
// TODO: Refactor media loading flow to simplify.
// Only in loading glTF Image, Video, and Audio flows,
// specified parameters assignment is needed after loading
// content then using MediaImage/VideoLoaderData as like
// transporting data from the inflators. This may be like
// special and a bit less maintainable.
switch(mediaType) {
case MediaType.IMAGE:
return yield* loadImage(
world,
accessibleUrl,
contentType,
MediaImageLoaderData.has(eid) ? MediaImageLoaderData.get(eid)! : {}
);
case MediaType.VIDEO:
return yield* loadVideo(
world,
accessibleUrl,
contentType,
MediaVideoLoaderData.has(eid) ? MediaVideoLoaderData.get(eid)! : {}
);
case MediaType.MODEL:
return yield* loadModel(world, accessibleUrl, contentType, true);
case MediaType.PDF:
return yield* loadPDF(world, accessibleUrl);
case MediaType.AUDIO:
return yield* loadAudio(
world,
accessibleUrl,
MediaVideoLoaderData.has(eid) ? MediaVideoLoaderData.get(eid)! : {}
);
case MediaType.HTML:
return yield* loadHtml(world, canonicalUrl, thumbnail);
default:
throw new UnsupportedMediaTypeError(eid, mediaType);
}
}

function* loadMedia(world: HubsWorld, eid: EntityID) {
let loadingObjEid = 0;
const addLoadingObjectTimeout = crTimeout(() => {
@@ -200,11 +226,7 @@ function* loadMedia(world: HubsWorld, eid: EntityID) {
let media: EntityID;
try {
const urlData = (yield resolveMediaInfo(src)) as MediaInfo;
const loader = urlData.mediaType && loaderForMediaType[urlData.mediaType];
if (!loader) {
throw new UnsupportedMediaTypeError(eid, urlData.mediaType);
}
media = yield* loader(world, eid, urlData);
media = yield* loadByMediaType(world, eid, urlData);
addComponent(world, MediaLoaded, media);
} catch (e) {
console.error(e);
@@ -257,6 +279,14 @@ export function mediaLoadingSystem(world: HubsWorld) {

mediaLoaderExitQuery(world).forEach(function (eid) {
jobs.stop(eid);

if (MediaImageLoaderData.has(eid)) {
MediaImageLoaderData.delete(eid);
}

if (MediaVideoLoaderData.has(eid)) {
MediaVideoLoaderData.delete(eid);
}
});

jobs.tick();
2 changes: 1 addition & 1 deletion src/inflators/image-loader.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { HubsWorld } from "../app";
import { MediaImageLoaderData } from "../bit-components";
import { ProjectionMode } from "../utils/projection-mode";
import { inflateMediaLoader } from "./media-loader";
import { MediaImageLoaderData } from "../bit-components";

This comment has been minimized.

Copy link
@takahirox

takahirox Aug 14, 2023

Author Contributor

Just for the consistent import order with video-loader.ts.


export interface ImageLoaderParams {
src: string;
40 changes: 25 additions & 15 deletions src/utils/load-audio.tsx
Original file line number Diff line number Diff line change
@@ -5,22 +5,32 @@ import { renderAsEntity } from "../utils/jsx-entity";
import { loadAudioTexture } from "../utils/load-audio-texture";
import { HubsWorld } from "../app";
import { HubsVideoTexture } from "../textures/HubsVideoTexture";
import { EntityID } from "./networking-types";
import { MediaVideoLoaderData } from "../bit-components";
import { VideoLoaderParams } from "../inflators/video-loader";

export function* loadAudio(world: HubsWorld, eid: EntityID, url: string) {
let loop = true;
let autoPlay = true;
let controls = true;
let projection = ProjectionMode.FLAT;
if (MediaVideoLoaderData.has(eid)) {
const params = MediaVideoLoaderData.get(eid)! as VideoLoaderParams;
loop = params.loop;
autoPlay = params.autoPlay;
controls = params.controls;
MediaVideoLoaderData.delete(eid);
}
type Params = {
loop?: boolean;
autoPlay?: boolean;
controls?: boolean;
projection?: ProjectionMode;
};

const DEFAULTS: Required<Params> = {
loop: true,
autoPlay: true,
controls: true,
projection: ProjectionMode.FLAT
};

export function* loadAudio(
world: HubsWorld,
url: string,
params: Params
) {
const {
loop,
autoPlay,
controls,
projection
} = Object.assign({}, DEFAULTS, params);

const { texture, ratio, video }: { texture: HubsVideoTexture; ratio: number; video: HTMLVideoElement } =
yield loadAudioTexture(url, loop, autoPlay);
37 changes: 28 additions & 9 deletions src/utils/load-image.tsx
Original file line number Diff line number Diff line change
@@ -6,8 +6,6 @@ import { renderAsEntity } from "../utils/jsx-entity";
import { HubsWorld } from "../app";
import { Texture } from "three";
import { AlphaMode } from "./create-image-mesh";
import { EntityID } from "./networking-types";
import { MediaImageLoaderData } from "../bit-components";
import { ImageParams } from "../inflators/image";

export function* createImageDef(world: HubsWorld, url: string, contentType: string): Generator<any, ImageParams, any> {
@@ -34,15 +32,36 @@ export function* createImageDef(world: HubsWorld, url: string, contentType: stri
};
}

export function* loadImage(world: HubsWorld, eid: EntityID, url: string, contentType: string) {
type Params = {
alphaCutoff?: number;
alphaMode?: AlphaMode;
projection?: ProjectionMode;
};

export function* loadImage(
world: HubsWorld,
url: string,
contentType: string,
params: Params
) {
const {
alphaCutoff,
alphaMode,
projection
} = params;

const imageDef = yield* createImageDef(world, url, contentType);

if (MediaImageLoaderData.has(eid)) {
const params = MediaImageLoaderData.get(eid)!;
imageDef.projection = params.projection as ProjectionMode;
imageDef.alphaMode = params.alphaMode as AlphaMode;
imageDef.alphaCutoff = params.alphaCutoff;
MediaImageLoaderData.delete(eid);
if (alphaCutoff !== undefined) {
imageDef.alphaCutoff = alphaCutoff;
}

if (alphaMode !== undefined) {
imageDef.alphaMode = alphaMode;
}

if (projection !== undefined) {
imageDef.projection = projection;
}

return renderAsEntity(world, <entity name="Image" image={imageDef} />);
42 changes: 26 additions & 16 deletions src/utils/load-video.tsx
Original file line number Diff line number Diff line change
@@ -5,23 +5,33 @@ import { renderAsEntity } from "../utils/jsx-entity";
import { loadVideoTexture } from "../utils/load-video-texture";
import { HubsWorld } from "../app";
import { HubsVideoTexture } from "../textures/HubsVideoTexture";
import { EntityID } from "./networking-types";
import { MediaVideoLoaderData } from "../bit-components";
import { VideoLoaderParams } from "../inflators/video-loader";

export function* loadVideo(world: HubsWorld, eid: EntityID, url: string, contentType: string) {
let loop = true;
let autoPlay = true;
let controls = true;
let projection = ProjectionMode.FLAT;
if (MediaVideoLoaderData.has(eid)) {
const params = MediaVideoLoaderData.get(eid)! as VideoLoaderParams;
loop = params.loop;
autoPlay = params.autoPlay;
controls = params.controls;
projection = params.projection!;
MediaVideoLoaderData.delete(eid);
}
type Params = {
loop?: boolean;
autoPlay?: boolean;
controls?: boolean;
projection?: ProjectionMode;
};

const DEFAULTS: Required<Params> = {
loop: true,
autoPlay: true,
controls: true,
projection: ProjectionMode.FLAT
};

export function* loadVideo(
world: HubsWorld,
url: string,
contentType: string,
params: Params
) {
const {
loop,
autoPlay,
controls,
projection
} = Object.assign({}, DEFAULTS, params);

const { texture, ratio, video }: { texture: HubsVideoTexture; ratio: number; video: HTMLVideoElement } =
yield loadVideoTexture(url, contentType, loop, autoPlay);

0 comments on commit 7dc5aed

Please sign in to comment.