UNPKG

polygonjs-engine

Version:

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

284 lines (253 loc) 8.71 kB
import {Number2, PolyDictionary} from '../../../../types/GlobalTypes'; import {TypedNode} from '../../../nodes/_Base'; import {SceneJsonExporter} from './Scene'; import {NodeContext} from '../../../poly/NodeContext'; import {JsonExportDispatcher} from './Dispatcher'; import {ParamJsonExporterData} from '../../../nodes/utils/io/IOController'; import {ParamType} from '../../../poly/ParamType'; import {BaseConnectionPointData} from '../../../nodes/utils/io/connections/_Base'; // revert to using index instead of name // for gl nodes such as the if node, whose input names // changes depending on the input interface NamedInputData { index: number; node: string; output: string; } type IndexedInputData = string | null; export type InputData = NamedInputData | IndexedInputData; interface FlagsData { bypass?: boolean; display?: boolean; optimize?: boolean; } export interface IoConnectionPointsData { in?: BaseConnectionPointData[]; out?: BaseConnectionPointData[]; } export interface NodeJsonExporterData { type: string; nodes?: PolyDictionary<NodeJsonExporterData>; children_context?: NodeContext; params?: PolyDictionary<ParamJsonExporterData<ParamType>>; inputs?: InputData[]; connection_points?: IoConnectionPointsData; selection?: string[]; flags?: FlagsData; cloned_state_overriden?: boolean; persisted_config?: object; } export interface NodeJsonExporterUIData { pos?: Number2; comment?: string; nodes: PolyDictionary<NodeJsonExporterUIData>; } type BaseNodeTypeWithIO = TypedNode<NodeContext, any>; export interface DataRequestOption { showPolyNodesData?: boolean; } export class NodeJsonExporter<T extends BaseNodeTypeWithIO> { private _data: NodeJsonExporterData | undefined; // = {} as NodeJsonExporterData; constructor(protected _node: T) {} data(options: DataRequestOption = {}): NodeJsonExporterData { if (!this.is_root()) { this._node.scene().nodesController.register_node_context_signature(this._node); } this._data = { type: this._node.type(), } as NodeJsonExporterData; // const required_imports = this._node.required_imports() // if(required_imports){ // this._data['required_imports'] = required_imports // } const nodes_data = this.nodes_data(options); if (Object.keys(nodes_data).length > 0) { this._data['nodes'] = nodes_data; // required by the Store::Scene::Exporter.rb // Update: removed as there should be a better way // const context = this._node.childrenController?.context; // if (context) { // this._data['children_context'] = context; // } } if (!this.is_root()) { const params_data = this.params_data(); if (Object.keys(params_data).length > 0) { this._data['params'] = params_data; } //data['custom'] = [] const inputs_data = this.inputs_data(); if (inputs_data.length > 0) { this._data['inputs'] = inputs_data; } const connection_points_data = this.connection_points_data(); if (connection_points_data) { this._data['connection_points'] = connection_points_data; } } if (this._node.flags) { const flags_data: FlagsData = {}; if (this._node.flags.has_bypass() || this._node.flags.has_display() || this._node.flags.has_optimize()) { if (this._node.flags.has_bypass()) { if (this._node.flags.bypass?.active()) { flags_data['bypass'] = this._node.flags.bypass.active(); } } if (this._node.flags.has_display()) { // only save the display flag if it is true, or if the parent does not have a display_node_controller // This will then always save it for OBJ // And only if true for SOP if (this._node.flags.display?.active() || !this._node.parent()?.display_node_controller) { flags_data['display'] = this._node.flags.display?.active(); } } if (this._node.flags.has_optimize()) { if (this._node.flags.optimize?.active()) { flags_data['optimize'] = this._node.flags.optimize?.active(); } } } if (Object.keys(flags_data).length > 0) { this._data['flags'] = flags_data; } } if (this._node.childrenAllowed()) { const selection = this._node.childrenController?.selection; if (selection && this._node.children().length > 0) { // only save the nodes that are still present, in case the selection just got deleted const selected_children: BaseNodeTypeWithIO[] = []; const selected_ids: PolyDictionary<boolean> = {}; for (let selected_node of selection.nodes()) { selected_ids[selected_node.graphNodeId()] = true; } for (let child of this._node.children()) { if (child.graphNodeId() in selected_ids) { selected_children.push(child); } } const selection_data = selected_children.map((n) => n.name()); if (selection_data.length > 0) { this._data['selection'] = selection_data; } } } // inputs clone if (this._node.io.inputs.override_cloned_state_allowed()) { const overriden = this._node.io.inputs.cloned_state_overriden(); if (overriden) { this._data['cloned_state_overriden'] = overriden; } } // persisted config if (this._node.persisted_config) { const persisted_config_data = this._node.persisted_config.toJSON(); if (persisted_config_data) { this._data.persisted_config = persisted_config_data; } } // custom this.add_custom(); return this._data; } ui_data(options: DataRequestOption = {}): NodeJsonExporterUIData { const data: NodeJsonExporterUIData = this.ui_data_without_children(); const children = this._node.children(); if (children.length > 0) { data['nodes'] = {}; children.forEach((child) => { const node_exporter = JsonExportDispatcher.dispatch_node(child); //.visit(JsonExporterVisitor); //.json_exporter() data['nodes'][child.name()] = node_exporter.ui_data(options); }); } return data; } protected ui_data_without_children(): NodeJsonExporterUIData { const data: NodeJsonExporterUIData = {} as NodeJsonExporterUIData; if (!this.is_root()) { const ui_data = this._node.uiData; data['pos'] = ui_data.position().toArray() as Number2; const comment = ui_data.comment(); if (comment) { data['comment'] = SceneJsonExporter.sanitize_string(comment); } } return data; } private is_root() { return this._node.parent() === null && this._node.graphNodeId() == this._node.root().graphNodeId(); } protected inputs_data() { const data: InputData[] = []; this._node.io.inputs.inputs().forEach((input, input_index) => { if (input) { const connection = this._node.io.connections.input_connection(input_index)!; if (this._node.io.inputs.has_named_inputs) { // const input_name = this._node.io.inputs.named_input_connection_points[input_index].name; const output_index = connection.output_index; const output_name = input.io.outputs.named_output_connection_points[output_index]?.name(); if (output_name) { data[input_index] = { index: input_index, node: input.name(), output: output_name, }; } } else { data[input_index] = input.name(); } } }); return data; } protected connection_points_data() { if (!this._node.io.has_connection_points_controller) { return; } if (!this._node.io.connection_points.initialized()) { return; } if (this._node.io.inputs.has_named_inputs || this._node.io.outputs.has_named_outputs) { const data: IoConnectionPointsData = {}; if (this._node.io.inputs.has_named_inputs) { data['in'] = []; for (let cp of this._node.io.inputs.named_input_connection_points) { if (cp) { data['in'].push(cp.toJSON()); } } } if (this._node.io.outputs.has_named_outputs) { data['out'] = []; for (let cp of this._node.io.outputs.named_output_connection_points) { if (cp) { data['out'].push(cp.toJSON()); } } } return data; } } protected params_data() { const data: PolyDictionary<ParamJsonExporterData<ParamType>> = {}; for (let param_name of this._node.params.names) { const param = this._node.params.get(param_name); if (param && !param.parent_param) { const param_exporter = JsonExportDispatcher.dispatch_param(param); if (param_exporter.required()) { const params_data = param_exporter.data(); data[param.name()] = params_data; } } } return data; } protected nodes_data(options: DataRequestOption = {}) { const data: PolyDictionary<NodeJsonExporterData> = {}; for (let child of this._node.children()) { const node_exporter = JsonExportDispatcher.dispatch_node(child); //.json_exporter() data[child.name()] = node_exporter.data(options); } return data; } protected add_custom() {} }