UNPKG

@polygonjs/polygonjs

Version:

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

284 lines (283 loc) 11.3 kB
"use strict"; import { DEFAULT_CONNECTION_POINT_ENUM_MAP, createConnectionPoint } from "./connections/ConnectionMap"; import { ConnectionPointsSpareParamsController } from "./ConnectionPointsSpareParamsController"; import { NetworkChildNodeType } from "../../../poly/NodeContext"; import { arrayCopy } from "../../../../core/ArrayUtils"; function arraysMatch(array0, array1) { if (array0.length != array1.length) { return false; } for (let i = 0; i < array0.length; i++) { if (array0[i] != array1[i]) { return false; } } return true; } export class ConnectionPointsController { constructor(node, _context) { this.node = node; this._context = _context; this._create_spare_params_from_inputs = true; this._functions_overridden = false; this._input_name_function = (index) => { return `in${index}`; }; this._output_name_function = (index) => { return index == 0 ? "val" : `val${index}`; }; // private _default_input_type: ConnectionPointType = ConnectionPointType.FLOAT; this._expected_input_types_function = () => { const type = this.first_input_connection_type() || this.default_connection_type(); return [type, type]; }; this._expected_output_types_function = () => { return [this._expected_input_types_function()[0]]; }; this._update_signature_if_required_bound = this.update_signature_if_required.bind(this); this._initialized = false; // used when a node changes its signature, adn the output nodes need to adapt their own signatures this._successorsCopy = []; this._spare_params_controller = new ConnectionPointsSpareParamsController(this.node, this._context); } default_connection_type() { return DEFAULT_CONNECTION_POINT_ENUM_MAP[this._context]; } createConnectionPoint(name, type) { return createConnectionPoint(this._context, name, type); } functions_overridden() { return this._functions_overridden; } initialized() { return this._initialized; } set_create_spare_params_from_inputs(state) { this._create_spare_params_from_inputs = state; } set_input_name_function(func) { this._initialize_if_required(); this._input_name_function = func; } set_output_name_function(func) { this._initialize_if_required(); this._output_name_function = func; } // set_default_input_type(type: ConnectionPointType) { // this._default_input_type = type; // } set_expected_input_types_function(func) { this._initialize_if_required(); this._functions_overridden = true; this._expected_input_types_function = func; } set_expected_output_types_function(func) { this._initialize_if_required(); this._functions_overridden = true; this._expected_output_types_function = func; } input_name(index) { return this._wrapped_input_name_function(index); } output_name(index) { return this._wrapped_output_name_function(index); } initializeNode() { if (this._initialized) { console.warn("already initialized", this.node); return; } this._initialized = true; this.node.io.inputs.add_on_set_input_hook( "_update_signature_if_required", this._update_signature_if_required_bound ); this.node.params.addOnSceneLoadHook("_update_signature_if_required", this._update_signature_if_required_bound); this.node.params.onParamsCreated( "_update_signature_if_required_bound", this._update_signature_if_required_bound ); this.node.addPostDirtyHook("_update_signature_if_required", this._update_signature_if_required_bound); if (!this._spare_params_controller.initialized()) { this._spare_params_controller.initializeNode(); } } _initialize_if_required() { if (!this._initialized) { this.initializeNode(); } } get spare_params() { return this._spare_params_controller; } update_signature_if_required() { if (!this.node.lifecycle.creationCompleted() || !this._inputsOutputsMatchExpectations()) { this.update_connection_types(); this.node.removeDirtyState(); if (!this.node.scene().loadingController.isLoading()) { this.make_successors_update_signatures(); } } } make_successors_update_signatures() { const successors = this.node.graphAllSuccessors(); arrayCopy(successors, this._successorsCopy); if (this.node.childrenAllowed()) { const subnet_inputs = this.node.nodesByType(NetworkChildNodeType.INPUT); const subnet_outputs = this.node.nodesByType(NetworkChildNodeType.OUTPUT); for (const subnet_input of subnet_inputs) { this._successorsCopy.push(subnet_input); } for (const subnet_output of subnet_outputs) { this._successorsCopy.push(subnet_output); } } for (const graphNode of this._successorsCopy) { const node = graphNode; if (node.io && node.io.has_connection_points_controller && node.io.connection_points.initialized()) { node.io.connection_points.update_signature_if_required(); } } } update_connection_types() { const set_dirty = false; const expected_input_types = this._wrapped_expected_input_types_function(); const expected_output_types = this._wrapped_expected_output_types_function(); const named_input_connection_points = []; for (let i = 0; i < expected_input_types.length; i++) { const type = expected_input_types[i]; const point = this.createConnectionPoint(this._wrapped_input_name_function(i), type); named_input_connection_points.push(point); } const named_output_connect_points = []; for (let i = 0; i < expected_output_types.length; i++) { const type = expected_output_types[i]; const point = this.createConnectionPoint(this._wrapped_output_name_function(i), type); named_output_connect_points.push(point); } this.node.io.inputs.setNamedInputConnectionPoints(named_input_connection_points); this.node.io.outputs.setNamedOutputConnectionPoints(named_output_connect_points, set_dirty); if (this._create_spare_params_from_inputs) { this._spare_params_controller.createSpareParameters(); } } _inputsOutputsMatchExpectations() { const namedInputConnections = this.node.io.inputs.namedInputConnectionPoints(); const namedOutputConnections = this.node.io.outputs.namedOutputConnectionPoints(); if (!(namedInputConnections && namedOutputConnections)) { return false; } const inputTypesMatch = arraysMatch( // make sure to test the expected ones against all except the inNodeDefinition ones namedInputConnections.filter((c) => !(c == null ? void 0 : c.inNodeDefinition())).map((c) => c == null ? void 0 : c.type()), this._wrapped_expected_input_types_function() ); const outputTypesMatch = arraysMatch( namedOutputConnections.map((c) => c == null ? void 0 : c.type()), this._wrapped_expected_output_types_function() ); const inputNamesMatch = arraysMatch( // make sure to test the expected ones against all except the inNodeDefinition ones namedInputConnections.filter((c) => !(c == null ? void 0 : c.inNodeDefinition())).map((c) => c == null ? void 0 : c.name()), namedInputConnections.filter((c) => !(c == null ? void 0 : c.inNodeDefinition())).map((c, i) => this._wrapped_input_name_function(i)) ); const outputNamesMatch = arraysMatch( namedOutputConnections.map((c) => c == null ? void 0 : c.name()), namedOutputConnections.map((c, i) => this._wrapped_output_name_function(i)) ); return inputTypesMatch && outputTypesMatch && inputNamesMatch && outputNamesMatch; } // // // WRAPPPED METHOD // the goal here is to use the types data saved in the scene file // when the scene is loading. That has 2 purposes: // - avoid an update cascade during loading, where nodes with many inputs are updated // several times. // - allow the subnet_input to load with the connection_points it had on save, // which in turn allows connected nodes to not lose their connections. // _wrapped_expected_input_types_function() { if (this.node.scene().loadingController.isLoading()) { const in_data = this.node.io.saved_connection_points_data.in(); if (in_data) { return in_data.map((d) => d.type); } } return this._expected_input_types_function(); } _wrapped_expected_output_types_function() { if (this.node.scene().loadingController.isLoading()) { const out_data = this.node.io.saved_connection_points_data.out(); if (out_data) { return out_data.map((d) => d.type); } } return this._expected_output_types_function(); } _wrapped_input_name_function(index) { if (this.node.scene().loadingController.isLoading()) { const in_data = this.node.io.saved_connection_points_data.in(); if (in_data) { return in_data[index].name; } } return this._input_name_function(index); } _wrapped_output_name_function(index) { if (this.node.scene().loadingController.isLoading()) { const out_data = this.node.io.saved_connection_points_data.out(); if (out_data) { return out_data[index].name; } } return this._output_name_function(index); } // protected input_connection_type() { // return this.first_input_connection_type(); // } // protected output_connection_type() { // return this.first_input_connection_type(); // } first_input_connection_type() { return this.input_connection_type(0); } input_connection_type(index) { const connections = this.node.io.connections.inputConnections(); if (!connections) { return; } const connection = connections[index]; if (!connection) { return; } const connectionPoint = connection.srcConnectionPoint(); if (!connectionPoint) { return; } return connectionPoint.type(); } // input_connection_point_from_connection(connection: TypedNodeConnection<NC>): ConnectionPointTypeMap[NC] { // const node_dest = connection.node_dest; // const output_index = connection.output_index; // return node_dest.io.outputs.namedOutputConnectionPoints()[output_index] as ConnectionPointTypeMap[NC]; // } // output_connection_point_from_connection(connection: TypedNodeConnection<NC>): ConnectionPointTypeMap[NC] { // const node_src = connection.node_src; // const output_index = connection.output_index; // return node_src.io.outputs.namedOutputConnectionPoints()[output_index] as ConnectionPointTypeMap[NC]; // } // connection_point_type_from_connection(connection: TypedNodeConnection<NC>): ConnectionPointEnumMap[NC] { // return connection.dest_connection_point()?.type as ConnectionPointEnumMap[NC]; // // const connection_point = this.output_connection_point_from_connection(connection)!; // // return connection_point.type as ConnectionPointEnumMap[NC]; // } // connection_point_name_from_connection(connection: TypedNodeConnection<NC>): string { // return connection.dest_connection_point()!.name // // const connection_point = this.output_connection_point_from_connection(connection)!; // // return connection_point.name; // } }