@polygonjs/polygonjs
Version:
node-based WebGL 3D engine https://polygonjs.com
200 lines (199 loc) • 6.72 kB
JavaScript
"use strict";
import { RootLoadProgressController } from "./../../nodes/manager/utils/Scene/LoadProgress";
import { isString } from "../../../core/Type";
import { TimeController } from "../../scene/utils/TimeController";
import { PolyEventsDispatcher } from "../common/EventsDispatcher";
import { PolyEventName } from "../../poly/utils/PolyEventName";
import { PROGRESS_RATIO } from "../common/Progress";
import { SceneJsonImporter } from "../json/import/Scene";
export class ScenePlayerImporter {
// private _cameraCreatorNode: BaseNodeType | null = null;
constructor(options) {
this.options = options;
this._onLoadCompleteCalled = false;
this._progress = 0;
this._viewerMarkedAsReady = false;
this._sceneMarkedAsReady = false;
this._debug2("new ScenePlayerImporter", options);
}
static async loadSceneData(options) {
const scenePlayerImporter = new ScenePlayerImporter(options);
const scene = await scenePlayerImporter.loadScene(options.serializers);
return {
scene,
viewer: scenePlayerImporter._viewer
};
}
async _onLoadComplete(scene) {
if (this._onLoadCompleteCalled == true) {
return;
}
this._onLoadCompleteCalled = true;
if (this._viewer) {
this._markViewerAsReady(this._viewer);
}
await this._markSceneAsReady(scene);
}
_markViewerAsReady(viewer) {
if (this._viewerMarkedAsReady) {
return;
}
this._viewerMarkedAsReady = true;
viewer.markAsReady();
this._dispatchEvent(PolyEventName.VIEWER_READY);
}
async _markSceneAsReady(scene) {
if (this._sceneMarkedAsReady) {
return;
}
this._sceneMarkedAsReady = true;
await scene.cookController.waitForCooksCompleted();
scene.setFrame(TimeController.START_FRAME);
if (this.options.autoPlay != false) {
scene.play();
}
scene.loadingController.dispatchReadyEvent();
this._dispatchEvent(PolyEventName.SCENE_READY);
}
_onNodesCookProgress(nodesCookProgress, args) {
const progressRatio = PROGRESS_RATIO.nodes;
const onProgress = (_ratio, args2) => {
var _a;
const progress = progressRatio.start + progressRatio.mult * _ratio;
this._progress = progress;
if (this.options.onProgress) {
this.options.onProgress(progress, args2);
}
PolyEventsDispatcher.dispatchProgressEvent(progress, (_a = this._scene) == null ? void 0 : _a.name());
};
onProgress(nodesCookProgress, args);
if (nodesCookProgress >= 1) {
this._onLoadComplete(args.scene);
}
}
async _watchNodesProgress(scene) {
scene.root().loadProgress.watchNodesProgress((nodesCookProgress, args) => {
this._onNodesCookProgress(nodesCookProgress, args);
});
}
async loadScene(options) {
const createSceneAndWaitForCameraCreatorNode = () => {
return new Promise(async (resolve) => {
const configureScene = this.options.configureScene;
const importer = new SceneJsonImporter(this.options.sceneData, {
sceneName: this.options.sceneName,
configureScene,
nodeCookWatcher: (scene3) => {
this._watchNodesProgress(scene3);
}
});
const scene2 = importer.scene(options);
scene2.timeController.forbidPlayUntilAllNodesCooked();
this._scene = scene2;
this._dispatchEvent(PolyEventName.SCENE_CREATED);
if (this.options.renderer) {
scene2.renderersRegister.registerRenderer(this.options.renderer);
}
const onCameraUpdated = async () => {
const camera = await scene2.camerasController.mainCamera({
findAnyCamera: false,
printCameraNotFoundError: this._progress >= 1,
// we display a warning if progress is 1
cameraMaskOverride: this.options.cameraMaskOverride
});
this._debug2("scene.camerasController:", {
camera,
cameraPath: scene2.root().mainCameraController.rawCameraPath()
});
if (camera) {
if (this._onCameraCreatorNodeLoadedResolve) {
this._onCameraCreatorNodeLoadedResolve();
}
}
};
this._onCameraCreatorNodeLoadedResolve = () => {
scene2.camerasController.removeOnCameraObjectsUpdated(onCameraUpdated);
resolve(scene2);
};
scene2.camerasController.onCameraObjectsUpdated(onCameraUpdated);
});
};
this._scene = await createSceneAndWaitForCameraCreatorNode();
const scene = this._scene;
const createViewer = async () => {
const domElement = this._domElement();
let createViewer2 = false;
if (this.options.createViewer != null) {
createViewer2 = this.options.createViewer;
}
if (domElement || createViewer2) {
this._viewer = await scene.camerasController.createMainViewer({
autoRender: false,
renderer: this.options.renderer,
cameraMaskOverride: this.options.cameraMaskOverride
});
if (this._viewer) {
if (domElement) {
this._viewer.mount(domElement);
}
if (this._sceneMarkedAsReady == true) {
this._markViewerAsReady(this._viewer);
}
this._dispatchEvent(PolyEventName.VIEWER_MOUNTED);
}
}
};
await createViewer();
return scene;
}
_domElement() {
const domElement = this.options.domElement;
if (domElement) {
if (isString(domElement)) {
const element = document.getElementById(domElement);
if (element) {
return element;
}
} else {
return domElement;
}
}
}
_dispatchEvent(eventName) {
this._debug2("_dispatchEvent", { eventName, scene: this._scene, viewer: this._viewer });
const elements = [this._domElement(), document];
if (!this._scene) {
console.warn(`no event emitted as no scene preset`);
return;
}
const detail = {
scene: this._scene,
viewer: this._viewer
};
const createEvent = (customEventName) => {
return new CustomEvent(customEventName, {
detail
});
};
for (let element of elements) {
if (element) {
element.dispatchEvent(createEvent(eventName));
if (this._scene) {
element.dispatchEvent(createEvent(`${eventName}-${this._scene.name()}`));
}
}
}
}
_debug(arg0) {
ScenePlayerImporter._debug(arg0);
}
_debug2(arg0, arg1) {
ScenePlayerImporter._debug2(arg0, arg1);
}
static _debug(arg0) {
RootLoadProgressController.debug(arg0);
}
static _debug2(arg0, arg1) {
RootLoadProgressController.debug2(arg0, arg1);
}
}