UNPKG

@polygonjs/polygonjs

Version:

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

197 lines (177 loc) 7.14 kB
import {CoreFeaturesController} from './../../../../core/FeaturesController'; import {NodeJsonExporterData} from './../export/Node'; import {BaseNodeType} from './../../../nodes/_Base'; import {NodeContext} from './../../../poly/NodeContext'; import {PolyNodeController} from './../../../nodes/utils/poly/PolyNodeController'; import {PolyScene} from '../../../scene/PolyScene'; // import {JsonImporterVisitor} from './Visitor' import {SceneJsonExporterData} from '../export/Scene'; import {JsonImportDispatcher} from './Dispatcher'; import {ImportReport} from './ImportReport'; import {OperationsComposerSopNode} from '../../../nodes/sop/OperationsComposer'; import {TimeController} from '../../../scene/utils/TimeController'; import {ParamJsonImporter} from './Param'; import {NodeCreateOptions} from '../../../nodes/utils/hierarchy/ChildrenController'; import {ROOT_NODE_NAME} from '../../../nodes/manager/Root'; import {CoreNodeSerializer} from '../../../nodes/utils/CoreNodeSerializer'; import {CoreParamSerializer} from '../../../params/utils/CoreParamSerializer'; import type {ParamType} from '../../../poly/ParamType'; export type ConfigureSceneCallback = (scene: PolyScene) => void; export type NodeCookWatchCallback = (scene: PolyScene) => void; export interface SerializerOptions { nodeSerializerClass: typeof CoreNodeSerializer; paramsSerializerClass: typeof CoreParamSerializer<ParamType>; } interface SceneJSONImporterOptions { sceneName?: string; configureScene?: ConfigureSceneCallback; nodeCookWatcher?: NodeCookWatchCallback; measurePerformanceOnLoad?: boolean; serializers?: SerializerOptions; } interface MigrateHelper { migrateData: (data: SceneJsonExporterData) => SceneJsonExporterData; migrateNodeType: (parentNode: BaseNodeType, nodeData: NodeJsonExporterData) => string; migrateParams: (parentNode: BaseNodeType, nodeData: NodeJsonExporterData) => void; } export class SceneJsonImporter { public readonly report = new ImportReport(this); private _base_operations_composer_nodes_with_resolve_required: OperationsComposerSopNode[] | undefined; constructor(private _data: SceneJsonExporterData, private _options?: SceneJSONImporterOptions) {} static async loadData(data: SceneJsonExporterData, options?: SceneJSONImporterOptions) { const importer = new SceneJsonImporter(data, options); return await importer.scene(options?.serializers); } private _migrateHelper: MigrateHelper | undefined; setMigrateHelper(migrateHelper: MigrateHelper) { this._migrateHelper = migrateHelper; } migrateHelper() { return this._migrateHelper; } oldPolygonjsSceneVersion() { const properties = this._data['properties']; if (properties) { return properties.versions?.polygonjs; } } scene(options?: SerializerOptions): PolyScene { if (this._migrateHelper) { this._data = this._migrateHelper.migrateData(this._data); } if (CoreFeaturesController.debugLoadProgress()) { console.log(`polygonjs version:${this.oldPolygonjsSceneVersion()}`); } const rootData = this._data['root']!; const paramsInitValueOverrides = ParamJsonImporter.non_spare_params_data_value(rootData['params']); const nodeCreateOptions: NodeCreateOptions = { paramsInitValueOverrides, nodeName: ROOT_NODE_NAME, serializerClass: options?.nodeSerializerClass, }; const embeddedPolyNodes = this._data.embeddedPolyNodes; if (embeddedPolyNodes) { const keys = Object.keys(embeddedPolyNodes); for (let key of keys) { const elements = key.split('/'); const nodeContext = elements[0] as NodeContext; const nodeType = elements[1]; const data = embeddedPolyNodes[key]; PolyNodeController.createNodeClassAndRegister({ node_context: nodeContext, node_type: nodeType, data, }); } } const scene = new PolyScene({root: nodeCreateOptions, paramsSerializerClass: options?.paramsSerializerClass}); if (this._options) { if (this._options.sceneName) { scene.setName(this._options.sceneName); } if (this._options.measurePerformanceOnLoad == true) { scene.performance.start(); } } scene.loadingController.markAsLoading(); // scene.set_js_version(this._data['__js_version']) const properties = this._data['properties']; if (properties) { // properties.versions?.polygonjs // scene.setName(properties['name']) const maxFrame = properties['maxFrame'] || 600; scene.timeController.setMaxFrame(maxFrame); const maxFrameLocked = properties['maxFrameLocked']; if (maxFrameLocked) { scene.timeController.setMaxFrameLocked(maxFrameLocked); } const realtimeState = properties['realtimeState']; if (realtimeState != null) { scene.timeController.setRealtimeState(realtimeState); } // set frame after the range has been set, to avoid clamping scene.setFrame(properties['frame'] || TimeController.START_FRAME); // scene.time_controller.set_fps(properties['fps'] || 30); const mainCameraPath = properties['mainCameraNodePath'] || properties['mainCameraPath']; if (mainCameraPath) { scene.camerasController.setMainCameraPath(mainCameraPath); } } // we block to ensure that nodes will not run their dirty_hooks // which would trigger operator_path params to search for nodes that // may not exist yet scene.cooker.block(); this._base_operations_composer_nodes_with_resolve_required = undefined; const dispatcher = new JsonImportDispatcher(); const importer = dispatcher.dispatchNode(scene.root()); if (rootData) { importer.process_data(this, rootData); } const uiData = this._data['ui']; if (uiData) { importer.process_ui_data(this, uiData); } this._resolve_operation_containers_with_path_param_resolve(); if (this._options) { if (this._options.nodeCookWatcher) { this._options.nodeCookWatcher(scene); } if (this._options.configureScene) { // make sure configureScene is called after the setName above this._options.configureScene(scene); } } scene.loadingController.markAsLoaded(); scene.cooker.unblock(); // DO NOT wait for cooks here, // as a viewer will only be created once everything has cooked // which would be a problem for envMap or other nodes relying on the renderer being created // await scene.waitForCooksCompleted(); return scene; } shadersData() { return this._data['shaders']; } jsFunctionBodiesData() { return this._data['jsFunctionBodies']; } // // // OPERATION CONTAINER RESOLVE // // add_operations_composer_node_with_path_param_resolve_required(operations_composer_node: OperationsComposerSopNode) { if (!this._base_operations_composer_nodes_with_resolve_required) { this._base_operations_composer_nodes_with_resolve_required = []; } this._base_operations_composer_nodes_with_resolve_required.push(operations_composer_node); } private _resolve_operation_containers_with_path_param_resolve() { if (!this._base_operations_composer_nodes_with_resolve_required) { return; } for (let operations_composer_node of this._base_operations_composer_nodes_with_resolve_required) { operations_composer_node.resolveOperationContainersPathParams(); } } }