UNPKG

@polygonjs/polygonjs

Version:

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

312 lines (311 loc) 11.9 kB
"use strict"; import { CoreString } from "../../../../core/String"; import { NodeEvent } from "../../../poly/NodeEvent"; import { CoreNodeSelection } from "../../../../core/NodeSelection"; import { Poly } from "../../../Poly"; import { SopOperationContainer } from "../../../operations/container/sop"; import { addToSetAtEntry, pushOnArrayAtEntry, removeFromSetAtEntry, popFromArrayAtEntry } from "../../../../core/MapUtils"; import { NameController } from "../NameController"; import { arrayCopy } from "../../../../core/ArrayUtils"; export class HierarchyChildrenController { constructor(node, _context) { this.node = node; this._context = _context; this._childrenByName = /* @__PURE__ */ new Map(); this._childrenIdByType = /* @__PURE__ */ new Map(); this._childrenByType = /* @__PURE__ */ new Map(); this._childrenAndGrandchildrenByContext = /* @__PURE__ */ new Map(); this._children = []; this._childrenNames = []; } get selection() { return this._selection = this._selection || new CoreNodeSelection(this.node); } dispose() { const _tmpChildren = []; arrayCopy(this.children(), _tmpChildren); for (const child of _tmpChildren) { this.node.removeNode(child); } _tmpChildren.length = 0; this._selection = void 0; } get context() { return this._context; } setOutputNodeFindMethod(method) { this._outputNodeFindMethod = method; } outputNode() { if (this._outputNodeFindMethod) { return this._outputNodeFindMethod(); } } // // // // // setChildName(node, newName) { let currentChildWithName; newName = CoreString.sanitizeName(newName); if ((currentChildWithName = this._childrenByName.get(newName)) != null) { if (node.name() === newName && currentChildWithName.graphNodeId() === node.graphNodeId()) { return; } newName = CoreString.increment(newName); return this.setChildName(node, newName); } else { const currentName = node.name(); const currentChild = this._childrenByName.get(currentName); if (currentChild) { this._childrenByName.delete(currentName); } this._childrenByName.set(newName, node); this._updateCache(); node.nameController.updateNameFromParent(newName); this.node.scene().nodesController.addToInstanciatedNode(node); this.node.scene().graphNodesController.notifyNodePathChanged(node); } } _nextAvailableChildName(nodeName) { nodeName = CoreString.sanitizeName(nodeName); return this._childrenByName.get(nodeName) ? this._nextAvailableChildName(CoreString.increment(nodeName)) : nodeName; } nodeContextSignature() { return `${this.node.context()}/${this.node.type()}`; } availableChildrenClasses() { return Poly.registeredNodes(this.node); } isValidChildType(node_type) { const node_class = this.availableChildrenClasses()[node_type]; return node_class != null; } // create_node(node_type: string, options?: NodeCreateOptions): BaseNodeType { // const node_class = this.available_children_classes()[node_type]; // if (node_class == null) { // const message = `child node type '${node_type}' not found for node '${this.node.path()}'. Available types are: ${Object.keys( // this.available_children_classes() // ).join(', ')}, ${this._context}, ${this.node.type}`; // console.error(message); // throw message; // } else { // const child_node = new node_class(this.node.scene, `child_node_${node_type}`, paramsInitValueOverrides); // child_node.initialize_base_and_node(); // this.add_node(child_node); // child_node.lifecycle.set_creation_completed(); // return child_node; // } // } createNode(nodeClassOrString, options) { if (typeof nodeClassOrString == "string") { const nodeClass = this._findNodeClass(nodeClassOrString); return this._createAndInitNode(nodeClass, options); } else { return this._createAndInitNode(nodeClassOrString, options); } } _createAndInitNode(nodeClass, options) { var _a; const requestedNodeName = (options == null ? void 0 : options.nodeName) || NameController.baseName(nodeClass); const nodeName = this._nextAvailableChildName(requestedNodeName); const childNode = new nodeClass(this.node.scene(), nodeName, { ...options, serializerClass: (_a = this.node.serializer) == null ? void 0 : _a.constructor }); childNode.initializeBaseAndNode(); this._addNode(childNode); childNode.lifecycle.setCreationCompleted(); return childNode; } _findNodeClass(node_type) { const nodeClass = this.availableChildrenClasses()[node_type.toLowerCase()]; if (nodeClass == null) { const message = `child node type '${node_type}' not found for node '${this.node.path()}'. Available types are: ${Object.keys( this.availableChildrenClasses() ).join(", ")}, ${this._context}, ${this.node.type()}`; console.error(message); throw message; } return nodeClass; } createOperationContainer(operationType, operationContainerName, options) { const operationClass = Poly.registeredOperation(this._context, operationType); if (operationClass == null) { const message = `no operation found with context ${this._context}/${operationType}`; console.error(message); throw message; } else { const operation = new operationClass(this.node.scene()); const operation_container = new SopOperationContainer( operation, operationContainerName, (options == null ? void 0 : options.paramsInitValueOverrides) || {} ); return operation_container; } } _addNode(childNode) { childNode.setParent(this.node); this._addToNodesByType(childNode); childNode.params.init(); childNode.parentController.onSetParent(); childNode.nameController.runPostSetFullPathHooks(); if (childNode.childrenAllowed() && childNode.childrenController) { for (const child of childNode.childrenController.children()) { child.nameController.runPostSetFullPathHooks(); } } if (this.node.serializer) { const childNodeJSON = childNode.toJSON(); if (childNodeJSON) { this.node.emit(NodeEvent.CREATED, { child_node_json: childNodeJSON }); } } if (this.node.scene().lifecycleController.onAfterCreatedCallbackAllowed()) { childNode.lifecycle.runOnAfterCreatedCallbacks(); } childNode.lifecycle.runOnAfterAddedCallbacks(); this.node.lifecycle.runOnChildAddCallbacks(childNode); if (childNode.requireWebGL2()) { this.node.scene().webglController.setRequireWebGL2(); } this.node.scene().missingExpressionReferencesController.checkForMissingNodeReferences(childNode); return childNode; } removeNode(childNode) { var _a; if (this.node.lockedOrInsideALockedParent()) { const lockedNode = this.node.selfOrLockedParent(); const reason = lockedNode == this.node ? `it is locked` : `it is inside '${lockedNode ? lockedNode.path() : ""}', which is locked`; console.warn(`node '${this.node.path()}' cannot remove nodes, since ${reason}`); console.log(this.node.graphNodeId(), this.node.name()); return; } if (childNode.parent() != this.node) { return console.warn(`node ${childNode.name()} not under parent ${this.node.path()}`); } else { (_a = childNode.polyNodeController) == null ? void 0 : _a.setLockedState(false); childNode.lifecycle.runOnBeforeDeleteCallbacks(); if (this.selection.contains(childNode)) { this.selection.remove([childNode]); } const firstConnection = childNode.io.connections.firstInputConnection(); const inputConnections = childNode.io.connections.inputConnections(); const outputConnections = []; childNode.io.connections.outputConnections(outputConnections); if (inputConnections) { for (const inputConnection of inputConnections) { if (inputConnection) { inputConnection.disconnect({ setInput: true }); } } } if (outputConnections) { for (const outputConnection of outputConnections) { if (outputConnection) { outputConnection.disconnect({ setInput: true }); if (firstConnection) { const oldSrc = firstConnection.nodeSrc(); const oldOutputIndex = firstConnection.outputIndex(); const oldDest = outputConnection.nodeDest(); const oldInputIndex = outputConnection.inputIndex(); oldDest.io.inputs.setInput(oldInputIndex, oldSrc, oldOutputIndex); } } } } childNode.setParent(null); this._childrenByName.delete(childNode.name()); this._updateCache(); this._removeFromNodesByType(childNode); this.node.scene().nodesController.removeFromInstanciatedNode(childNode); childNode.setSuccessorsDirty(this.node); childNode.graphDisconnectSuccessors(); this.node.lifecycle.runOnChildRemoveCallbacks(childNode); childNode.lifecycle.runOnDeleteCallbacks(); childNode.dispose(); childNode.emit(NodeEvent.DELETED, { parent_id: this.node.graphNodeId() }); this.node.scene().graphNodesController.notifyNodePathChanged(childNode); } } _addToNodesByType(node) { const nodeId = node.graphNodeId(); const type = node.type(); addToSetAtEntry(this._childrenIdByType, type, nodeId); pushOnArrayAtEntry(this._childrenByType, type, node); this._addToChildrenAndGrandchildrenByContext(node); } _removeFromNodesByType(node) { const nodeId = node.graphNodeId(); const type = node.type(); removeFromSetAtEntry(this._childrenIdByType, type, nodeId); popFromArrayAtEntry(this._childrenByType, type, node); this._removeFromChildrenAndGrandchildrenByContext(node); } _addToChildrenAndGrandchildrenByContext(node) { var _a; const nodeId = node.graphNodeId(); const nodeContext = node.context(); addToSetAtEntry(this._childrenAndGrandchildrenByContext, nodeContext, nodeId); const parent = this.node.parent(); if (parent && parent.childrenAllowed()) { (_a = parent.childrenController) == null ? void 0 : _a._addToChildrenAndGrandchildrenByContext(node); } } _removeFromChildrenAndGrandchildrenByContext(node) { var _a; const nodeId = node.graphNodeId(); const type = node.context(); removeFromSetAtEntry(this._childrenAndGrandchildrenByContext, type, nodeId); const parent = this.node.parent(); if (parent && parent.childrenAllowed()) { (_a = parent.childrenController) == null ? void 0 : _a._removeFromChildrenAndGrandchildrenByContext(node); } } nodesByType(type, target = []) { const nodes = this._childrenByType.get(type); target.length = nodes ? nodes.length : 0; if (nodes) { for (let i = 0; i < nodes.length; i++) { target[i] = nodes[i]; } } return target; } childByName(name) { return this._childrenByName.get(name) || null; } hasChildrenAndGrandchildrenWithContext(context) { return this._childrenAndGrandchildrenByContext.get(context) != null; } _updateCache() { this._children.length = 0; this._childrenNames.length = 0; this._childrenByName.forEach((node) => { this._children.push(node); this._childrenNames.push(node.name()); }); } children() { return this._children; } childrenNames() { return this._childrenNames; } traverseChildren(callback, conditionCallback) { this._childrenByName.forEach((childNode) => { var _a; callback(childNode); if (conditionCallback == null || conditionCallback(childNode) == true) { (_a = childNode.childrenController) == null ? void 0 : _a.traverseChildren(callback); } }); } }