polygonjs-engine
Version:
node-based webgl 3D engine https://polygonjs.com
359 lines (323 loc) • 11.7 kB
text/typescript
import {TypedNode} from '../../../nodes/_Base';
import {Vector2} from 'three/src/math/Vector2';
import {JsonImportDispatcher} from './Dispatcher';
import {ParamType} from '../../../poly/ParamType';
import {ParamsUpdateOptions} from '../../../nodes/utils/params/ParamsController';
import {SceneJsonImporter} from '../../../io/json/import/Scene';
import {NodeContext} from '../../../poly/NodeContext';
import {NodeJsonExporterData, NodeJsonExporterUIData, InputData, IoConnectionPointsData} from '../export/Node';
import {
ParamJsonExporterData,
SimpleParamJsonExporterData,
ComplexParamJsonExporterData,
} from '../../../nodes/utils/io/IOController';
import {NodesJsonImporter} from './Nodes';
import {Poly} from '../../../Poly';
import {CoreType} from '../../../../core/Type';
import {ObjectUtils} from '../../../../core/ObjectUtils';
import {CoreString} from '../../../../core/String';
import {PolyDictionary} from '../../../../types/GlobalTypes';
const COMPLEX_PARAM_DATA_KEYS: Readonly<string[]> = ['overriden_options', 'type'];
type BaseNodeTypeWithIO = TypedNode<NodeContext, any>;
export class NodeJsonImporter<T extends BaseNodeTypeWithIO> {
constructor(protected _node: T) {}
process_data(scene_importer: SceneJsonImporter, data: NodeJsonExporterData) {
this.set_connection_points(data['connection_points']);
// rather than having the children creation dependent on the persisted config and player mode, use the childrenAllowed() method
// const skip_create_children = Poly.playerMode() && data.persisted_config;
if (this._node.childrenAllowed()) {
this.create_nodes(scene_importer, data['nodes']);
}
this.set_selection(data['selection']);
// inputs clone
if (this._node.io.inputs.override_cloned_state_allowed()) {
const override = data['cloned_state_overriden'];
if (override) {
this._node.io.inputs.override_cloned_state(override);
}
}
this.set_flags(data);
// params
// const spare_params_data = ParamJsonImporter.spare_params_data(data['params']);
// this.set_params(spare_params_data);
this.set_params(data['params']);
if (data.persisted_config) {
this.set_persisted_config(data.persisted_config);
}
this.from_data_custom(data);
// already called in create_node()
// this._node.lifecycle.set_creation_completed();
}
process_inputs_data(data: NodeJsonExporterData) {
this.setInputs(data['inputs']);
}
process_ui_data(scene_importer: SceneJsonImporter, data: NodeJsonExporterUIData) {
if (!data) {
return;
}
if (Poly.playerMode()) {
return;
}
const ui_data = this._node.uiData;
const pos = data['pos'];
if (pos) {
const vector = new Vector2().fromArray(pos);
ui_data.setPosition(vector);
}
const comment = data['comment'];
if (comment) {
ui_data.setComment(comment);
}
if (this._node.childrenAllowed()) {
this.process_nodes_ui_data(scene_importer, data['nodes']);
}
}
create_nodes(scene_importer: SceneJsonImporter, data?: PolyDictionary<NodeJsonExporterData>) {
if (!data) {
return;
}
const nodes_importer = new NodesJsonImporter(this._node);
nodes_importer.process_data(scene_importer, data);
}
set_selection(data?: string[]) {
if (this._node.childrenAllowed() && this._node.childrenController) {
if (data && data.length > 0) {
const selected_nodes: BaseNodeTypeWithIO[] = [];
data.forEach((node_name) => {
const node = this._node.node(node_name);
if (node) {
selected_nodes.push(node);
}
});
this._node.childrenController.selection.set(selected_nodes);
}
}
}
set_flags(data: NodeJsonExporterData) {
const flags = data['flags'];
if (flags) {
const bypass = flags['bypass'];
if (bypass != null) {
this._node.flags?.bypass?.set(bypass);
}
const display = flags['display'];
if (display != null) {
this._node.flags?.display?.set(display);
}
const optimize = flags['optimize'];
if (optimize != null) {
this._node.flags?.optimize?.set(optimize);
}
}
}
set_connection_points(connection_points_data: IoConnectionPointsData | undefined) {
if (!connection_points_data) {
return;
}
if (connection_points_data['in']) {
this._node.io.saved_connection_points_data.set_in(connection_points_data['in']);
}
if (connection_points_data['out']) {
this._node.io.saved_connection_points_data.set_out(connection_points_data['out']);
}
if (this._node.io.has_connection_points_controller) {
this._node.io.connection_points.update_signature_if_required();
}
}
setInputs(inputs_data?: InputData[]) {
if (!inputs_data) {
return;
}
let input_data: InputData;
for (let i = 0; i < inputs_data.length; i++) {
input_data = inputs_data[i];
if (input_data && this._node.parent()) {
if (CoreType.isString(input_data)) {
const input_node_name = input_data;
const input_node = this._node.nodeSibbling(input_node_name);
this._node.setInput(i, input_node);
} else {
const input_node = this._node.nodeSibbling(input_data['node']);
const input_index = input_data['index'];
this._node.setInput(input_index, input_node, input_data['output']);
}
}
}
}
process_nodes_ui_data(scene_importer: SceneJsonImporter, data: PolyDictionary<NodeJsonExporterUIData>) {
if (!data) {
return;
}
if (Poly.playerMode()) {
return;
}
const node_names = Object.keys(data);
for (let node_name of node_names) {
const node = this._node.node(node_name);
if (node) {
const node_data = data[node_name];
JsonImportDispatcher.dispatch_node(node).process_ui_data(scene_importer, node_data);
// node.visit(JsonImporterVisitor).process_ui_data(node_data);
}
}
}
//
//
// PARAMS
//
//
set_params(data?: PolyDictionary<ParamJsonExporterData<ParamType>>) {
if (!data) {
return;
}
const param_names = Object.keys(data);
const params_update_options: ParamsUpdateOptions = {};
for (let param_name of param_names) {
const param_data = data[param_name] as ComplexParamJsonExporterData<ParamType>;
const options = param_data['options'];
// const is_spare = options && options['spare'] === true;
// make camelCase if required
if (false && param_name.includes('_')) {
param_name = CoreString.camelCase(param_name);
}
const param_type = param_data['type']!;
const has_param = this._node.params.has_param(param_name);
let has_param_and_same_type = false;
let param;
if (has_param) {
param = this._node.params.get(param_name);
// we can safely consider same type if param_type is not mentioned
if ((param && param.type() == param_type) || param_type == null) {
has_param_and_same_type = true;
}
}
if (has_param_and_same_type) {
if (this._is_param_data_complex(param_data)) {
this._process_param_data_complex(param_name, param_data);
} else {
this._process_param_data_simple(param_name, param_data as SimpleParamJsonExporterData<ParamType>);
}
} else {
// it the param is a spare one,
// we check if it is currently exists with same type first.
// - if it is, we only update the value
// - if it's not, we delete it and add it again
params_update_options.names_to_delete = params_update_options.names_to_delete || [];
params_update_options.names_to_delete.push(param_name);
params_update_options.to_add = params_update_options.to_add || [];
params_update_options.to_add.push({
name: param_name,
type: param_type,
init_value: param_data['default_value'] as any,
raw_input: param_data['raw_input'] as any,
options: options,
});
// if (options && param_type) {
// if (param_data['default_value']) {
// if (has_param) {
// this._node.params.delete_param(param_name);
// }
// param = this._node.add_param(param_type, param_name, param_data['default_value'], options);
// if (param) {
// JsonImportDispatcher.dispatch_param(param).process_data(param_data);
// }
// }
// }
}
}
// delete and create the spare params we need to
const params_delete_required =
params_update_options.names_to_delete && params_update_options.names_to_delete.length > 0;
const params_add_required = params_update_options.to_add && params_update_options.to_add.length > 0;
if (params_delete_required || params_add_required) {
this._node.params.update_params(params_update_options);
// update them based on the imported data
for (let spare_param of this._node.params.spare) {
const param_data = data[spare_param.name()] as ComplexParamJsonExporterData<ParamType>;
// JsonImportDispatcher.dispatch_param(spare_param).process_data(param_data);
if (!spare_param.parent_param && param_data) {
if (this._is_param_data_complex(param_data)) {
this._process_param_data_complex(spare_param.name(), param_data);
} else {
this._process_param_data_simple(
spare_param.name(),
param_data as SimpleParamJsonExporterData<ParamType>
);
}
}
}
}
// those hooks are useful for some gl nodes,
// such as the constant, which needs to update its connections
// based on another parameter, which will be set just before
this._node.params.run_on_scene_load_hooks();
}
private _process_param_data_simple(param_name: string, param_data: SimpleParamJsonExporterData<ParamType>) {
this._node.params.get(param_name)?.set(param_data);
}
private _process_param_data_complex(param_name: string, param_data: ComplexParamJsonExporterData<ParamType>) {
const param = this._node.params.get(param_name);
if (param) {
JsonImportDispatcher.dispatch_param(param).process_data(param_data);
}
// return
// const has_param = this._node.params.has_param(param_name);
// const param_type = param_data['type']!;
// let has_param_and_same_type = false;
// let param;
// if (has_param) {
// param = this._node.params.get(param_name);
// // we can safely consider same type if param_type is not mentioned
// if ((param && param.type == param_type) || param_type == null) {
// has_param_and_same_type = true;
// }
// }
// if (has_param_and_same_type) {
// param = this._node.params.get(param_name);
// if (param) {
// JsonImportDispatcher.dispatch_param(param).process_data(param_data);
// // param.visit(JsonImporterVisitor).process_data(param_data);
// }
// } else {
// const options = param_data['options'];
// if (options && param_type) {
// const is_spare = options['spare'] === true;
// if (is_spare && param_data['default_value']) {
// if (has_param) {
// this._node.params.delete_param(param_name);
// }
// param = this._node.add_param(param_type, param_name, param_data['default_value'], options);
// if (param) {
// JsonImportDispatcher.dispatch_param(param).process_data(param_data);
// }
// }
// }
// }
}
private _is_param_data_complex(param_data: ParamJsonExporterData<ParamType>): boolean {
// we can test here most param value serialized, except for ramp
if (
CoreType.isString(param_data) ||
CoreType.isNumber(param_data) ||
CoreType.isArray(param_data) ||
CoreType.isBoolean(param_data)
) {
return false;
}
if (ObjectUtils.isObject(param_data)) {
const keys = Object.keys(param_data);
for (let complex_key of COMPLEX_PARAM_DATA_KEYS) {
if (keys.includes(complex_key)) {
return true;
}
}
}
return false;
}
set_persisted_config(persisted_config_data: object) {
if (this._node.persisted_config) {
this._node.persisted_config.load(persisted_config_data);
}
}
from_data_custom(data: NodeJsonExporterData) {}
}