@polygonjs/polygonjs
Version:
node-based WebGL 3D engine https://polygonjs.com
164 lines (163 loc) • 6.06 kB
JavaScript
;
import { sanitizeUrl } from "../../../../core/UrlHelper";
import { PolyEventsDispatcher } from "../../common/EventsDispatcher";
import { PROGRESS_RATIO } from "../../common/Progress";
import { SelfContainedFileName } from "../../self_contained/Common";
function _shaderUrl(options) {
const { urlPrefix, nodePath, shaderName, timestamp } = options;
return `${urlPrefix}/root/${nodePath}.${shaderName}.glsl?t=${timestamp}`;
}
function _jsFunctionBodyUrl(options) {
const { urlPrefix, nodePath, timestamp } = options;
return `${urlPrefix}/root/${nodePath}.txt?t=${timestamp}`;
}
function _iterateShaders(manifest, callback) {
const shaderNodePaths = Object.keys(manifest.shaders);
for (let nodePath of shaderNodePaths) {
const nodeShaders = manifest.shaders[nodePath];
const nodeShaderNames = Object.keys(nodeShaders);
for (let shaderName of nodeShaderNames) {
const timestamp = nodeShaders[shaderName];
callback({ nodePath, shaderName, timestamp });
}
}
}
function _iterateFunctionBodies(manifest, callback) {
const nodePaths = Object.keys(manifest.jsFunctionBodies);
for (let nodePath of nodePaths) {
const timestamp = manifest.jsFunctionBodies[nodePath];
callback({ nodePath, timestamp });
}
}
export class SceneDataManifestImporter {
static async importSceneData(importData) {
if (importData.editorMode == null) {
importData.editorMode = false;
}
const manifest = importData.manifest;
const urlPrefix = importData.urlPrefix || SelfContainedFileName.CODE_PREFIX;
const nodePaths = Object.keys(manifest.nodes);
const nodeUrls = [];
for (let node_path of nodePaths) {
const timestamp = manifest.nodes[node_path];
const url = `${urlPrefix}/root/${node_path}.json?t=${timestamp}`;
nodeUrls.push(url);
}
const root_url = `${urlPrefix}/root.json?t=${manifest.root}`;
const properties_url = `${urlPrefix}/properties.json?t=${manifest.properties}`;
const allUrls = [root_url, properties_url];
if (importData.editorMode) {
const now = Date.now();
allUrls.push(`${urlPrefix}/ui.json?t=${now}`);
}
for (let nodeUrl of nodeUrls) {
allUrls.push(nodeUrl);
}
const shaderUrls = [];
_iterateShaders(manifest, (options) => {
const shaderUrl = _shaderUrl({ urlPrefix, ...options });
allUrls.push(shaderUrl);
shaderUrls.push(shaderUrl);
});
const jsFunctionBodiesUrls = [];
_iterateFunctionBodies(manifest, (options) => {
const jsFunctionBodyUrl = _jsFunctionBodyUrl({ urlPrefix, ...options });
allUrls.push(jsFunctionBodyUrl);
jsFunctionBodiesUrls.push(jsFunctionBodyUrl);
});
let count = 0;
const jsonPayloadsCount = allUrls.length - (shaderUrls.length + jsFunctionBodiesUrls.length);
const total = allUrls.length;
function _incrementCount() {
count++;
const ratio = count / total;
const progressRatio = PROGRESS_RATIO.sceneData;
const progress = progressRatio.start + progressRatio.mult * ratio;
if (importData.onProgress) {
importData.onProgress(progress);
}
PolyEventsDispatcher.dispatchProgressEvent(progress, importData.sceneName);
}
const sanitizedUrls = allUrls.map((url) => sanitizeUrl(url));
const promises = sanitizedUrls.map((url) => fetch(url));
const responses = await Promise.all(promises);
const jsonResponses = responses.slice(0, jsonPayloadsCount);
const textResponses = responses.slice(jsonPayloadsCount);
const results = await Promise.all([
...jsonResponses.map((response) => {
_incrementCount();
return response.json();
}),
...textResponses.map((response) => {
_incrementCount();
return response.text();
})
]);
const jsons = results.slice(0, jsonPayloadsCount);
const texts = results.slice(jsonPayloadsCount);
let textIndex = 0;
const shadersData = {};
_iterateShaders(manifest, (options) => {
const text = texts[textIndex];
const { nodePath, shaderName } = options;
shadersData[nodePath] = shadersData[nodePath] || {};
shadersData[nodePath][shaderName] = text;
textIndex++;
});
const jsFunctionBodiesData = {};
_iterateFunctionBodies(manifest, (options) => {
const text = texts[textIndex];
const { nodePath } = options;
jsFunctionBodiesData[nodePath] = text;
textIndex++;
});
const assembleData = {
root: jsons[0],
properties: jsons[1],
shaders: shadersData,
jsFunctionBodies: jsFunctionBodiesData
};
let responseOffset = 2;
if (importData.editorMode) {
assembleData["ui"] = jsons[2];
responseOffset += 1;
}
const jsonByName = {};
const manifestNodes = Object.keys(manifest.nodes);
for (let i = 0; i < manifestNodes.length; i++) {
const manifestName = manifestNodes[i];
const json = jsons[i + responseOffset];
jsonByName[manifestName] = json;
}
return this.assemble(assembleData, manifestNodes, jsonByName);
}
static async assemble(assembleData, manifestNodes, jsonByName) {
const sceneData = {
root: assembleData.root,
properties: assembleData.properties,
ui: assembleData.ui,
shaders: assembleData.shaders,
jsFunctionBodies: assembleData.jsFunctionBodies
};
for (let i = 0; i < manifestNodes.length; i++) {
const manifestName = manifestNodes[i];
const json = jsonByName[manifestName];
this._insertChildData(sceneData.root, manifestName, json);
}
return sceneData;
}
static _insertChildData(data, path, json) {
const elements = path.split("/");
if (elements.length == 1) {
if (!data.nodes) {
data.nodes = {};
}
data.nodes[path] = json;
} else {
const parentName = elements.shift();
const pathWithoutParent = elements.join("/");
const parentData = data.nodes[parentName];
this._insertChildData(parentData, pathWithoutParent, json);
}
}
}