Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add basic support for loading media with bitecs behind feature flag. #5677

Merged
merged 85 commits into from
Sep 2, 2022
Merged
Show file tree
Hide file tree
Changes from 55 commits
Commits
Show all changes
85 commits
Select commit Hold shift + click to select a range
4077884
[Work in progress] Load images without AFRAME
johnshaughnessy Aug 4, 2022
7885b32
Stub out video
johnshaughnessy Aug 9, 2022
87b0ef6
Add models to media-loading system
johnshaughnessy Aug 9, 2022
e95c2e7
Resize and recenter media after it loads
johnshaughnessy Aug 10, 2022
12e82d8
Add chain for sequential coroutines.
johnshaughnessy Aug 11, 2022
c07ccf4
Animate the proxy object
johnshaughnessy Aug 11, 2022
b7e9a9f
Start loading videos
johnshaughnessy Aug 12, 2022
b47b18b
Simplify coroutines and cancelables
johnshaughnessy Aug 16, 2022
3da1980
Use AbortControllers and AbortSignals
johnshaughnessy Aug 16, 2022
1e831b2
Merge remote-tracking branch 'origin/master' into feature/load-media
johnshaughnessy Aug 16, 2022
d5c6e95
Fix error handling in coroutine / cancelable
johnshaughnessy Aug 16, 2022
77554f8
Merge remote-tracking branch 'origin/add-typescript' into feature/loa…
johnshaughnessy Aug 16, 2022
cd6962f
Add networked video playback state
johnshaughnessy Aug 16, 2022
73af100
Separate the menus from the video entity
johnshaughnessy Aug 16, 2022
9a92bd8
Fix cursor hovering on video menu
johnshaughnessy Aug 17, 2022
8fc2978
Formatting
johnshaughnessy Aug 17, 2022
0346a37
Remove unused code
johnshaughnessy Aug 17, 2022
7df8801
Add type stub for troika-three-text
netpro2k Aug 17, 2022
9d94e7a
Convert jsx-entities to ts, type JSX better
netpro2k Aug 17, 2022
db63f2f
Minor type fixes
netpro2k Aug 17, 2022
1a98179
Fix taking ownership of loaded media
johnshaughnessy Aug 17, 2022
a75023e
Remove NOCOMMIT
johnshaughnessy Aug 17, 2022
889fefc
Add seek-slider to video
johnshaughnessy Aug 18, 2022
4392a9f
Update play/pause button label
johnshaughnessy Aug 18, 2022
c9e485d
Fix hovering on playhead
johnshaughnessy Aug 18, 2022
4816d40
Minor tweaks to video menu layout
netpro2k Aug 18, 2022
99f2a49
Intersecting In The Plane Of!
johnshaughnessy Aug 19, 2022
42d6e14
Basic audio playback for videos
netpro2k Aug 19, 2022
64965b9
Fix minor issue where time label is one frame late
johnshaughnessy Aug 19, 2022
91d3181
Rename mediaVideoSystem -> videoSystem
johnshaughnessy Aug 19, 2022
e920990
Toggle video play/pause on click. Grab to move.
johnshaughnessy Aug 22, 2022
91c620c
Fix action set toggle: Hands do not hover on videos
johnshaughnessy Aug 22, 2022
3a11b77
Add deleteEntitySystem
johnshaughnessy Aug 23, 2022
b85e4a9
Add animation to entity deletion
johnshaughnessy Aug 23, 2022
c5bb832
Add transparent play/pause indicators
johnshaughnessy Aug 23, 2022
caaa4b9
Merge branch 'add-typescript' into feature/load-media
netpro2k Aug 24, 2022
e9d552a
Fix asset imports by using babel-loader for TS
netpro2k Aug 24, 2022
4173296
Convert dash-case inflators to camelCase
netpro2k Aug 25, 2022
3615803
Support pasting files
johnshaughnessy Aug 25, 2022
8a2948f
Handle dropping files
johnshaughnessy Aug 26, 2022
ec02ce0
Add newloader query string param as feature flag
johnshaughnessy Aug 26, 2022
3c44d34
Fix classic video menus / interactions
johnshaughnessy Aug 26, 2022
08c8cf9
Update todo
johnshaughnessy Aug 26, 2022
dae8bf9
Remove todo file
johnshaughnessy Aug 26, 2022
6c5825a
Delete unused file
johnshaughnessy Aug 26, 2022
fd2ad95
Remove unused imports
johnshaughnessy Aug 26, 2022
8ce2940
Remove MediaLoader component after load
johnshaughnessy Aug 29, 2022
f8153d2
Undo change to cursor controller
johnshaughnessy Aug 29, 2022
98c2434
Fix grabbing videos
johnshaughnessy Aug 29, 2022
6c9d132
Remove unused animation mixer system
johnshaughnessy Aug 30, 2022
8a7c711
Add Constraint components for floaty-object
johnshaughnessy Aug 30, 2022
c60191d
Move utils/onpaste to load-media-on-paste-or-drop
johnshaughnessy Aug 30, 2022
80569f5
Add TextureCacheKey component.
johnshaughnessy Aug 30, 2022
df99c68
Warn on unrecognized component.
johnshaughnessy Aug 30, 2022
eec20d2
Fix button props
johnshaughnessy Aug 30, 2022
2c291b3
Use MediaParams in inflateMediaLoader
johnshaughnessy Aug 30, 2022
6f9f96b
Throw error if url parsing fails
johnshaughnessy Aug 30, 2022
11fcd85
Simplify function parameters
johnshaughnessy Aug 30, 2022
b5b81a6
Consolidate MEDIA_TYPE and MediaType
johnshaughnessy Aug 30, 2022
5e695e9
Simplify loader function signatures
johnshaughnessy Aug 30, 2022
157b0ea
Simplify loadVideoTexture parameters
johnshaughnessy Aug 30, 2022
b89f1e7
Remove unnecessary workaround
johnshaughnessy Aug 30, 2022
4edc977
Remove log
johnshaughnessy Aug 30, 2022
fc4b58c
Simplify method signatures
johnshaughnessy Aug 30, 2022
f3c31d2
Simplify function parameters
johnshaughnessy Aug 30, 2022
a35e2d1
Simplify function parameters
johnshaughnessy Aug 30, 2022
10680ea
Remove unused code
johnshaughnessy Aug 30, 2022
7a73e21
Use AnimationConfig type for calls to animate
johnshaughnessy Aug 30, 2022
e21a247
Remove unused code
johnshaughnessy Aug 30, 2022
9a4252e
Remove unnecessary workaround
johnshaughnessy Aug 30, 2022
b32448c
Avoid extra copy
johnshaughnessy Aug 30, 2022
8b1f2ce
Preload assets. Dry up model loading
johnshaughnessy Aug 31, 2022
c89a192
Rename MediaParams -> MediaLoaderParams
johnshaughnessy Aug 31, 2022
359cad5
Rename fetchUrlData -> resolveMediaInfo
johnshaughnessy Aug 31, 2022
c526275
Restore dontHoverAndHold.
johnshaughnessy Aug 31, 2022
d54c184
rename
johnshaughnessy Aug 31, 2022
df37251
Add ECS Debug sidebar on ecsDebug qs param
johnshaughnessy Aug 31, 2022
dbeeea6
Remove duplicate exclude block
netpro2k Sep 1, 2022
bea7e3f
delint
netpro2k Sep 1, 2022
a83deb6
Rename couroutine timer functions
netpro2k Sep 1, 2022
889a9c7
Fix video menu position updating issues
netpro2k Sep 1, 2022
8a89e6f
Merge remote-tracking branch 'origin/master' into feature/load-media
netpro2k Sep 1, 2022
a45e692
Fix ECS Debug button label
netpro2k Sep 2, 2022
59c7513
Clean up loading cube removal
netpro2k Sep 2, 2022
b92010f
Delint
netpro2k Sep 2, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions admin/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,17 @@ module.exports = (env, argv) => {
return /node_modules/.test(modulePath) && !/node_modules\/hubs/.test(modulePath);
}
},
{
// We use babel to handle typescript so that features are correctly polyfilled for our targeted browsers. It also ends up being
// a good deeal faster since it just strips out types. It does NOT typecheck. Typechecking is only done at build and (ideally) in your editor.
test: /\.tsx?$/,
loader: "babel-loader",
options: require("../babel.config"),
include: [path.resolve(__dirname, "src")],
exclude: function (modulePath) {
return /node_modules/.test(modulePath) && !/node_modules\/hubs/.test(modulePath);
}
},
// TODO worker-loader has been deprecated, but we need "inline" support which is not available yet
// ideally instead of inlining workers we should serve them off the root domain instead of CDN.
{
Expand Down
18 changes: 14 additions & 4 deletions babel.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,25 @@ module.exports = {
{
exclude: ["transform-regenerator"],
// targets are defined in .browserslistrc
// false = do not polyfill stuff unneccessarily
useBuiltIns: false
useBuiltIns: "entry",
// This should be kept up to date with thee version in package.json
corejs: "3.24.1",
// We care more about perf than exactly conforming to the spec
loose: true,
exclude: [
// These exist since forever but end up being polyfilled anyway because of an obscure issue if length is not writeable
"es.array.push",
"es.array.unshift"
],
// Enable to sse resolved targets and polyfills being used
debug: false
}
]
],
"@babel/typescript"
],
plugins: [
// TODO: When i18n build pipeline is finished move to: [ "react-intl", { "removeDefaultMessage": true } ]
"react-intl",
"transform-react-jsx-img-import",
["@babel/proposal-class-properties", { loose: true }],
["@babel/plugin-proposal-private-property-in-object", { loose: true }],
["@babel/plugin-proposal-private-methods", { loose: true }],
Expand Down
1,249 changes: 834 additions & 415 deletions package-lock.json

Large diffs are not rendered by default.

19 changes: 12 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,10 @@
"scripts": {
"info": "npm-scripts-info",
"start": "webpack serve --mode=development --env loadAppConfig=1",
"dev": "webpack serve --mode=development --env remoteDev=1",
"dev": "webpack serve --mode=development --env remoteDev=1 --progress",
"local": "webpack serve --mode=development --env localDev=1",
"build": "rimraf ./dist && webpack --mode=production",
"check": "tsc",
"build": "npm run check && rimraf ./dist && webpack --mode=production",
"bundle-analyzer": "webpack serve --mode=production --env dev=1 --env bundleAnalyzer=1",
"doc": "node ./scripts/doc/build.js",
"prettier": "prettier --write '*.js' 'src/**/*.js'",
Expand Down Expand Up @@ -84,7 +85,7 @@
"classnames": "^2.2.5",
"color": "^3.1.2",
"copy-to-clipboard": "^3.0.8",
"core-js": "^3.6.5",
"core-js": "^3.24.1",
"dashjs": "^3.1.0",
"deepmerge": "^2.1.1",
"detect-browser": "^3.0.1",
Expand Down Expand Up @@ -146,14 +147,14 @@
"zip-loader": "^1.1.0"
},
"devDependencies": {
"@babel/core": "^7.18.9",
"@babel/core": "^7.18.13",
"@babel/eslint-parser": "^7.18.9",
"@babel/plugin-proposal-class-properties": "^7.18.6",
"@babel/plugin-proposal-object-rest-spread": "^7.18.9",
"@babel/plugin-proposal-optional-chaining": "7.18.9",
"@babel/polyfill": "^7.4.4",
"@babel/preset-env": "^7.18.9",
"@babel/preset-env": "^7.18.10",
"@babel/preset-react": "^7.18.6",
"@babel/preset-typescript": "^7.18.6",
"@babel/register": "^7.18.9",
"@calm/eslint-plugin-react-intl": "^1.4.1",
"@formatjs/cli": "^5.0.6",
Expand All @@ -166,11 +167,12 @@
"@storybook/react": "^6.5.9",
"@storybook/storybook-deployer": "^2.8.12",
"@svgr/webpack": "^6.3.1",
"@types/three": "^0.141.0",
"@types/webxr": "^0.5.0",
"acorn": "^8.8.0",
"ava": "^4.3.1",
"babel-loader": "^8.2.5",
"babel-plugin-react-intl": "^8.2.21",
"babel-plugin-transform-react-jsx-img-import": "^0.1.4",
"copy-webpack-plugin": "^11.0.0",
"cors": "^2.8.5",
"css-loader": "^6.7.1",
Expand All @@ -184,6 +186,7 @@
"esm": "^3.2.25",
"fast-plural-rules": "1.0.2",
"file-loader": "^6.2.0",
"fork-ts-checker-webpack-plugin": "^7.2.13",
"fs-extra": "^10.1.0",
"glob": "^8.0.3",
"html-loader": "^4.1.0",
Expand Down Expand Up @@ -216,6 +219,8 @@
"stylelint-config-recommended-scss": "^7.0.0",
"stylelint-scss": "^4.3.0",
"tar": "^6.1.11",
"ts-loader": "^9.3.1",
"typescript": "^4.7.4",
"url-loader": "^4.1.1",
"webpack": "^5.74.0",
"webpack-bundle-analyzer": "^4.5.0",
Expand Down
156 changes: 104 additions & 52 deletions src/App.js → src/app.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,56 @@
import * as bitecs from "bitecs";
import { addEntity, createWorld } from "bitecs";
import { addEntity, createWorld, IWorld } from "bitecs";
import "./aframe-to-bit-components";
import { AEntity, Networked, Object3DTag, Owned } from "./bit-components";
import MediaSearchStore from "./storage/media-search-store";
import Store from "./storage/store";
import qsTruthy from "./utils/qs_truthy";

import type { AElement, AScene } from "aframe";
import HubChannel from "./utils/hub-channel";
import MediaDevicesManager from "./utils/media-devices-manager";

import {
Audio,
AudioListener,
Clock,
Object3D,
PerspectiveCamera,
PositionalAudio,
Scene,
sRGBEncoding,
WebGLRenderer
} from "three";
import { AudioSettings, SourceType } from "./components/audio-params";
import { DialogAdapter } from "./naf-dialog-adapter";

declare global {
interface Window {
$B: typeof bitecs;
$O: (eid: number) => Object3D | undefined;
APP: App;
}
const APP: App;
}

export interface HubsWorld extends IWorld {
scene: Scene;
nameToComponent: {
object3d: typeof Object3DTag;
networked: typeof Networked;
owned: typeof Owned;
AEntity: typeof AEntity;
};
ignoredNids: Set<number>;
deletedNids: Set<number>;
nid2eid: Map<number, number>;
eid2obj: Map<number, Object3D>;
time: { delta: number; elapsed: number; tick: number; then: number };
}

window.$B = bitecs;

const timeSystem = world => {
const timeSystem = (world: HubsWorld) => {
const { time } = world;
const now = performance.now();
const delta = now - time.then;
Expand All @@ -20,58 +62,68 @@ const timeSystem = world => {
};

export class App {
constructor() {
this.scene = null;
this.store = new Store();
this.mediaSearchStore = new MediaSearchStore();
this.hubChannel = null;
this.mediaDevicesManager = null;

// TODO: Remove comments
// TODO: Rename or reconfigure these as needed
this.audios = new Map(); // el -> (THREE.Audio || THREE.PositionalAudio)
this.sourceType = new Map(); // el -> SourceType
this.audioOverrides = new Map(); // el -> AudioSettings
this.zoneOverrides = new Map(); // el -> AudioSettings
this.audioDebugPanelOverrides = new Map(); // SourceType -> AudioSettings
this.sceneAudioDefaults = new Map(); // SourceType -> AudioSettings
this.gainMultipliers = new Map(); // el -> Number
this.supplementaryAttenuation = new Map(); // el -> Number
this.clippingState = new Set();
this.mutedState = new Set();
this.isAudioPaused = new Set();

this.world = createWorld();
scene?: AScene;
hubChannel?: HubChannel;
mediaDevicesManager?: MediaDevicesManager;

store = new Store();
mediaSearchStore = new MediaSearchStore();

audios = new Map<AElement | number, PositionalAudio | Audio>();
sourceType = new Map<AElement | number, SourceType>();
audioOverrides = new Map<AElement | number, AudioSettings>();
zoneOverrides = new Map<AElement | number, AudioSettings>();
gainMultipliers = new Map<AElement | number, number>();
supplementaryAttenuation = new Map<AElement | number, number>();
clippingState = new Set<AElement | number>();
mutedState = new Set<AElement | number>();
isAudioPaused = new Set<AElement | number>();
audioDebugPanelOverrides = new Map<SourceType, AudioSettings>();
sceneAudioDefaults = new Map<SourceType, AudioSettings>();

world: HubsWorld = createWorld();

str2sid: Map<string | null, number>;
sid2str: Map<number, string | null>;
nextSid = 1;

audioListener: AudioListener;

dialog = new DialogAdapter();

RENDER_ORDER = {
HUD_BACKGROUND: 1,
HUD_ICONS: 2,
CURSOR: 3
};

constructor() {
// TODO: Create accessor / update methods for these maps / set
this.world.eid2obj = new Map(); // eid -> Object3D
this.world.eid2obj = new Map();

this.world.nid2eid = new Map();
this.world.deletedNids = new Set();
this.world.ignoredNids = new Set();

this.str2sid = new Map([[null, 0]]);
this.sid2str = new Map([[0, null]]);
this.nextSid = 1;

window.$o = eid => {
this.world.eid2obj.get(eid);
};

// reserve entity 0 to avoid needing to check for undefined everywhere eid is checked for existance
addEntity(this.world);

// used in aframe and networked aframe to avoid imports
this.world.nameToComponent = {
object3d: Object3DTag,
networked: Networked,
owned: Owned,
AEntity
};

// reserve entity 0 to avoid needing to check for undefined everywhere eid is checked for existance
addEntity(this.world);

this.str2sid = new Map([[null, 0]]);
this.sid2str = new Map([[0, null]]);

window.$O = eid => this.world.eid2obj.get(eid);
}

// TODO nothing ever cleans these up
getSid(str) {
getSid(str: string) {
if (!this.str2sid.has(str)) {
const sid = this.nextSid;
this.nextSid = this.nextSid + 1;
Expand All @@ -82,25 +134,25 @@ export class App {
return this.str2sid.get(str);
}

getString(sid) {
getString(sid: number) {
return this.sid2str.get(sid);
}

// This gets called by a-scene to setup the renderer, camera, and audio listener
// TODO ideally the contorl flow here would be inverted, and we would setup this stuff,
// initialize aframe, and then run our own RAF loop
setupRenderer(sceneEl) {
setupRenderer(sceneEl: AScene) {
const canvas = document.createElement("canvas");
canvas.classList.add("a-canvas");
canvas.dataset.aframeCanvas = true;
canvas.dataset.aframeCanvas = "true";

// TODO this comes from aframe and prevents zoom on ipad.
// This should alreeady be handleed by disable-ios-zoom but it does not appear to work
canvas.addEventListener("touchmove", function(event) {
canvas.addEventListener("touchmove", function (event) {
event.preventDefault();
});

const renderer = new THREE.WebGLRenderer({
const renderer = new WebGLRenderer({
// TODO we should not be using alpha: false https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/WebGL_best_practices#avoid_alphafalse_which_can_be_expensive
alpha: true,
antialias: true,
Expand All @@ -120,49 +172,49 @@ export class App {

// These get overridden by environment-system but setting to the highly expected defaults to avoid any extra work
renderer.physicallyCorrectLights = true;
renderer.outputEncoding = THREE.sRGBEncoding;
renderer.outputEncoding = sRGBEncoding;

sceneEl.appendChild(renderer.domElement);

const camera = new THREE.PerspectiveCamera(80, window.innerWidth / window.innerHeight, 0.05, 10000);
const camera = new PerspectiveCamera(80, window.innerWidth / window.innerHeight, 0.05, 10000);

const audioListener = new THREE.AudioListener();
APP.audioListener = audioListener;
const audioListener = new AudioListener();
this.audioListener = audioListener;
camera.add(audioListener);

const renderClock = new THREE.Clock();
const renderClock = new Clock();

// TODO NAF currently depends on this, it should not
sceneEl.clock = renderClock;

// TODO we should have 1 source of truth for time
APP.world.time = {
this.world.time = {
delta: 0,
elapsed: 0,
then: performance.now(),
tick: 0
};

APP.world.scene = sceneEl.object3D;
this.world.scene = sceneEl.object3D;

// Main RAF loop
function mainTick(_rafTime, xrFrame) {
const mainTick = (_rafTime: number, xrFrame: XRFrame) => {
// TODO we should probably be using time from the raf loop itself
const delta = renderClock.getDelta() * 1000;
const time = renderClock.elapsedTime * 1000;

// TODO pass this into systems that care about it (like input) once they are moved into this loop
sceneEl.frame = xrFrame;

timeSystem(APP.world);
timeSystem(this.world);

// Tick AFrame systems and components
if (sceneEl.isPlaying) {
sceneEl.tick(time, delta);
}

renderer.render(sceneEl.object3D, camera);
}
};

// This gets called after all system and component init functions
sceneEl.addEventListener("loaded", () => {
Expand Down
2 changes: 1 addition & 1 deletion src/avatar.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import configs from "./utils/configs";
import { disableiOSZoom } from "./utils/disable-ios-zoom";
disableiOSZoom();

import { App } from "./App";
import { App } from "./app";

import AvatarPreview from "./react-components/avatar-preview";

Expand Down
Loading