@polygonjs/polygonjs
Version:
node-based WebGL 3D engine https://polygonjs.com
284 lines (283 loc) • 11.3 kB
JavaScript
"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;
// }
}