UNPKG

@polygonjs/polygonjs

Version:

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

495 lines (494 loc) 16.4 kB
"use strict"; import { TypedNodeConnection } from "./NodeConnection"; import { CoreGraphNode } from "../../../../core/graph/CoreGraphNode"; import { NodeEvent } from "../../../poly/NodeEvent"; import { ClonedStatesController } from "./utils/ClonedStatesController"; import { isString } from "../../../../core/Type"; import { arrayShallowClone } from "../../../../core/ArrayUtils"; const _existingInputIndices = []; const MAX_INPUTS_COUNT_UNSET = 0; export class NodeInputsController { // private _user_inputs_clonable_states: InputCloneMode[] | undefined; // private _inputs_clonable_states: InputCloneMode[] | undefined; // private _inputs_cloned_state: boolean[] = []; // private _override_clonable_state: boolean = false; constructor(node) { this.node = node; this._graphNodeInputs = []; this._inputs = []; this._has_named_inputs = false; this._minInputsCount = 0; this._maxInputsCount = MAX_INPUTS_COUNT_UNSET; this._maxInputsCountOnInput = MAX_INPUTS_COUNT_UNSET; this._depends_on_inputs = true; this._singleInputIndexListenedTo = null; } // clonable dispose() { if (this._graphNode) { this._graphNode.dispose(); } for (const graph_node of this._graphNodeInputs) { if (graph_node) { graph_node.dispose(); } } this._on_update_hooks = void 0; this._on_update_hook_names = void 0; } setDependsOnInputs(depends_on_inputs) { this._depends_on_inputs = depends_on_inputs; } setMinCount(minInputsCount) { this._minInputsCount = minInputsCount; } minCount() { return this._minInputsCount; } setMaxCount(maxInputsCount) { if (this._maxInputsCount == MAX_INPUTS_COUNT_UNSET) { this._maxInputsCountOnInput = maxInputsCount; } this._maxInputsCount = maxInputsCount; this._initGraphNodeInputs(); this._updateCloneRequiredState(); } listenToSingleInputIndex(index) { this._singleInputIndexListenedTo = index; } onEnsureListenToSingleInputIndexUpdated(callback) { this._onEnsureListenToSingleInputIndexUpdatedCallback = callback; } namedInputConnectionPointsByName(name) { if (this._named_input_connection_points) { for (const connection_point of this._named_input_connection_points) { if (connection_point && connection_point.name() == name) { return connection_point; } } } } setNamedInputConnectionPoints(newConnectionPoints) { var _a; this._has_named_inputs = true; const connectionPointsToKeep = ((_a = this._named_input_connection_points) == null ? void 0 : _a.filter((cp) => cp == null ? void 0 : cp.inNodeDefinition())) || []; const allNewConnectionPoints = arrayShallowClone(connectionPointsToKeep); const currentNames = /* @__PURE__ */ new Set(); for (const connectionPointToKeep of connectionPointsToKeep) { if (connectionPointToKeep) { currentNames.add(connectionPointToKeep.name()); } } for (const newConnectionPoint of newConnectionPoints) { if (newConnectionPoint) { if (!currentNames.has(newConnectionPoint.name())) { currentNames.add(newConnectionPoint.name()); allNewConnectionPoints.push(newConnectionPoint); } } } const connections = this.node.io.connections.inputConnections(); if (connections) { for (const connection of connections) { if (connection) { if (connection.inputIndex() >= allNewConnectionPoints.length) { connection.disconnect({ setInput: true, ignoreLockedState: true }); } } } } this._named_input_connection_points = allNewConnectionPoints; this.setMinCount(0); this.setMaxCount(this._named_input_connection_points.length); this._initGraphNodeInputs(); this.node.emit(NodeEvent.NAMED_INPUTS_UPDATED); } // private _has_connected_inputs() { // for (let input of this._inputs) { // if (input != null) { // return true; // } // } // return false; // } // private _check_name_changed(connection_points: ConnectionPointTypeMap[NC][]) { // if (this._named_input_connection_points) { // if (this._named_input_connection_points.length != connection_points.length) { // return true; // } else { // for (let i = 0; i < this._named_input_connection_points.length; i++) { // if (this._named_input_connection_points[i]?.name != connection_points[i]?.name) { // return true; // } // } // } // } // return false; // } hasNamedInputs() { return this._has_named_inputs; } namedInputConnectionPoints() { return this._named_input_connection_points; } _initGraphNodeInputs() { for (let i = 0; i < this._maxInputsCount; i++) { this._graphNodeInputs[i] = this._graphNodeInputs[i] || this._createGraphNodeInput(i); } } _createGraphNodeInput(index) { const graphInputNode = new CoreGraphNode(this.node.scene(), `input_${index}`); this.graphNode().addGraphInput(graphInputNode, false); return graphInputNode; } graphNode() { return this._graphNode = this._graphNode || this._createGraphNode(); } _createGraphNode() { const graphNode = new CoreGraphNode(this.node.scene(), "inputs"); this.node.addGraphInput(graphNode, false); return graphNode; } maxInputsCount() { return this._maxInputsCount || 0; } maxInputsCountOverriden() { return this._maxInputsCount != this._maxInputsCountOnInput; } inputGraphNode(input_index) { return this._graphNodeInputs[input_index]; } setCount(min, max) { if (max == null) { max = min; } this.setMinCount(min); this.setMaxCount(max); this._initConnectionControllerInputs(); } _initConnectionControllerInputs() { this.node.io.connections.initInputs(); } isGraphNodeDirty() { var _a; return ((_a = this._graphNode) == null ? void 0 : _a.isDirty()) || false; } _isAnyInputDirty() { for (const input of this._inputs) { if (input && input.isDirty()) { return true; } } return false; } containersWithoutEvaluation(target) { target.length = 0; for (let i = 0; i < this._inputs.length; i++) { const inputNode = this._inputs[i]; let container = null; if (inputNode) { container = inputNode.containerController.containerUnlessBypassed(); } target.push(container); } return target; } _existingInputIndices(target) { target.length = 0; if (this._maxInputsCount > 0) { for (let i = 0; i < this._inputs.length; i++) { if (this._inputs[i]) { target.push(i); } } } return target; } async evalRequiredInputs(target) { var _a; target.length = 0; if (this.node.disposed() == true) { return target; } if (this._maxInputsCount > 0) { this._existingInputIndices(_existingInputIndices); if (_existingInputIndices.length < this._minInputsCount) { this.node.states.error.set("inputs are missing"); } else { if (_existingInputIndices.length > 0) { if (this._onEnsureListenToSingleInputIndexUpdatedCallback) { await this._onEnsureListenToSingleInputIndexUpdatedCallback(); } if (this._maxInputsCount == 1) { const container = await this.evalRequiredInput(0); target.push(container); } else { const promises = []; if (this._singleInputIndexListenedTo != null) { promises.push( this.evalRequiredInput(this._singleInputIndexListenedTo) ); } else { const lastExistingInputIndex = _existingInputIndices[_existingInputIndices.length - 1]; for (let i = 0; i < this._inputs.length; i++) { const input = this._inputs[i]; if (input) { promises.push(this.evalRequiredInput(i)); } else { if (i <= lastExistingInputIndex) { promises.push(void 0); } } } } const results = await Promise.all(promises); for (const result of results) { target.push(result); } } if (!this._isAnyInputDirty()) { (_a = this._graphNode) == null ? void 0 : _a.removeDirtyState(); } } } } return target; } async evalRequiredInput(inputIndex) { let container = void 0; const inputNode = this.input(inputIndex); if (inputNode) { container = await inputNode.compute(); this._graphNodeInputs[inputIndex].removeDirtyState(); } if (container && container.coreContent()) { } else { if (inputNode) { const inputErrorMessage = inputNode.states.error.message(); if (inputErrorMessage && this.node.disposed() == false) { this.node.states.error.set(`input ${inputIndex} is invalid (error: ${inputErrorMessage})`); } } } return container; } getNamedInputIndex(name) { var _a; if (this._named_input_connection_points) { for (let i = 0; i < this._named_input_connection_points.length; i++) { if (((_a = this._named_input_connection_points[i]) == null ? void 0 : _a.name()) == name) { return i; } } } return -1; } getInputIndex(input_index_or_name) { if (isString(input_index_or_name)) { if (this.hasNamedInputs()) { return this.getNamedInputIndex(input_index_or_name); } else { throw new Error(`node ${this.node.path()} has no named inputs`); } } else { return input_index_or_name; } } setInput(inputIndexOrName, node, outputIndexOrName, options) { const ignoreLockedState = (options == null ? void 0 : options.ignoreLockedState) || false; if (ignoreLockedState == false && this.node.insideALockedParent()) { const lockedParent = this.node.lockedParent(); console.warn( `node '${this.node.path()}' cannot have its inputs changed, since it is inside '${lockedParent ? lockedParent.path() : ""}', which is locked` ); return; } if (outputIndexOrName == null) { outputIndexOrName = 0; } const noExceptionOnInvalidInput = (options == null ? void 0 : options.noExceptionOnInvalidInput) || false; const inputIndex = this.getInputIndex(inputIndexOrName) || 0; if (inputIndex < 0) { const message = `invalid input (${inputIndexOrName}) for node ${this.node.path()}`; if (!noExceptionOnInvalidInput) { console.warn(message); throw new Error(message); } else { return; } } let outputIndex = 0; if (node) { if (node.io.outputs.hasNamedOutputs()) { outputIndex = node.io.outputs.getOutputIndex(outputIndexOrName); if (outputIndex == null || outputIndex < 0) { const connection_points = node.io.outputs.namedOutputConnectionPoints(); const names = connection_points ? connection_points.map((cp) => cp.name()) : []; console.warn( `node ${node.path()} does not have an output named ${outputIndexOrName}. inputs are: ${names.join( ", " )}` ); return; } } const nodeParent = node.parent(); const currentNodeParent = this.node.parent(); if (!(nodeParent && currentNodeParent && nodeParent.graphNodeId() == currentNodeParent.graphNodeId())) { console.warn(`node ${node.path()} does not have the same parent as ${this.node.path()}`); return; } } const graphInputNode = this._graphNodeInputs[inputIndex]; if (graphInputNode == null) { const message = `no input at index ${inputIndex} (name: ${inputIndexOrName}) for node '${this.node.name()}' at path '${this.node.path()}'`; console.warn(message); throw new Error(message); } if (node && this.node.parent() != node.parent()) { return; } const oldInputNode = this._inputs[inputIndex]; let oldOutputIndex = null; let oldConnection = void 0; if (this.node.io.connections) { oldConnection = this.node.io.connections.inputConnection(inputIndex); } if (oldConnection) { oldOutputIndex = oldConnection.outputIndex(); } if (node !== oldInputNode || outputIndex != oldOutputIndex) { if (oldInputNode != null) { if (this._depends_on_inputs) { graphInputNode.removeGraphInput(oldInputNode); } } if (node != null) { const connectionResult = graphInputNode.addGraphInput(node); if (connectionResult) { if (!this._depends_on_inputs) { graphInputNode.removeGraphInput(node); } if (oldConnection) { oldConnection.disconnect({ setInput: false }); } this._inputs[inputIndex] = node; new TypedNodeConnection( node, this.node, outputIndex, inputIndex ); } else { console.warn(`cannot connect ${node.path()} to ${this.node.path()}`); } } else { this._inputs[inputIndex] = null; if (oldConnection) { oldConnection.disconnect({ setInput: false }); } } this._run_on_set_input_hooks(); graphInputNode.setSuccessorsDirty(); this.node.emit(NodeEvent.INPUTS_UPDATED); } } // remove_input(node: BaseNodeByContextMap[NC]) { // const inputs = this.inputs(); // let input: BaseNodeByContextMap[NC] | null; // for (let i = 0; i < inputs.length; i++) { // input = inputs[i]; // if (input != null && node != null) { // if (input.graphNodeId() === node.graphNodeId()) { // this.setInput(i, null); // } // } // } // } input(input_index) { return this._inputs[input_index]; } named_input(input_name) { if (this.hasNamedInputs()) { const input_index = this.getInputIndex(input_name); return this._inputs[input_index]; } else { return null; } } named_input_connection_point(input_name) { if (this.hasNamedInputs() && this._named_input_connection_points) { const input_index = this.getInputIndex(input_name); return this._named_input_connection_points[input_index]; } } has_named_input(name) { return this.getNamedInputIndex(name) >= 0; } hasInput(input_index) { return this._inputs[input_index] != null; } inputs() { return this._inputs; } initInputsClonedState(states) { if (!this._clonedStatesController) { this._clonedStatesController = new ClonedStatesController(this); this._clonedStatesController.initInputsClonedState(states); } } overrideClonedStateAllowed() { var _a; return ((_a = this._clonedStatesController) == null ? void 0 : _a.overrideClonedStateAllowed()) || false; } overrideClonedState(state) { var _a; (_a = this._clonedStatesController) == null ? void 0 : _a.overrideClonedState(state); } clonedStateOverriden() { var _a; return ((_a = this._clonedStatesController) == null ? void 0 : _a.overriden()) || false; } cloneRequired(index) { var _a; const state = (_a = this._clonedStatesController) == null ? void 0 : _a.cloneRequiredState(index); if (state != null) { return state; } return true; } cloneRequiredStates() { var _a; const states = (_a = this._clonedStatesController) == null ? void 0 : _a.cloneRequiredStates(); if (states != null) { return states; } return true; } _updateCloneRequiredState() { var _a; (_a = this._clonedStatesController) == null ? void 0 : _a.updateCloneRequiredState(); } // // // HOOKS // // add_on_set_input_hook(name, hook) { this._on_update_hooks = this._on_update_hooks || []; this._on_update_hook_names = this._on_update_hook_names || []; if (!this._on_update_hook_names.includes(name)) { this._on_update_hooks.push(hook); this._on_update_hook_names.push(name); } else { console.warn(`hook with name ${name} already exists`, this.node); } } _run_on_set_input_hooks() { if (this._on_update_hooks) { for (const hook of this._on_update_hooks) { hook(); } } } }