UNPKG

@polygonjs/polygonjs

Version:

node-based WebGL 3D engine https://polygonjs.com

164 lines (163 loc) 6.06 kB
"use strict"; 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); } } }