UNPKG

@polygonjs/polygonjs

Version:

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

203 lines (202 loc) 7.25 kB
"use strict"; import { TypedEventNode } from "./_Base"; import { EventConnectionPoint, EventConnectionPointType } from "../utils/io/connections/Event"; var CookMode = /* @__PURE__ */ ((CookMode2) => { CookMode2["ALL_TOGETHER"] = "all together"; CookMode2["BATCH"] = "batch"; return CookMode2; })(CookMode || {}); const COOK_MODES = ["all together" /* ALL_TOGETHER */, "batch" /* BATCH */]; import { NodeParamsConfig, ParamConfig } from "../utils/params/ParamsConfig"; import { TypeAssert } from "../../poly/Assert"; import { isBooleanTrue } from "../../../core/BooleanValue"; class NodeCookEventParamsConfig extends NodeParamsConfig { constructor() { super(...arguments); /** @param mask to select which nodes this will cook or listen to */ this.mask = ParamConfig.STRING("/geo*", { callback: (node) => { NodeCookEventNode.PARAM_CALLBACK_updateResolvedNodes(node); } }); /** @param forces cook of nodes mentioned in the mask param */ this.force = ParamConfig.BOOLEAN(0); /** @param defines if the nodes should cook one after the other or in parallel */ this.cookMode = ParamConfig.INTEGER(COOK_MODES.indexOf("all together" /* ALL_TOGETHER */), { menu: { entries: COOK_MODES.map((name, value) => { return { name, value }; }) } }); /** @param batch size */ this.batchSize = ParamConfig.INTEGER(1, { visibleIf: { cookMode: COOK_MODES.indexOf("batch" /* BATCH */) }, separatorAfter: true }); /** @param if on, we only trigger the first time a specific node has cooked. If false, we register every time a node cooks */ this.registerOnlyFirstCooks = ParamConfig.BOOLEAN(true); /** @param updates the list of nodes from the mask parameter. This can be useful if nodes are added or removed from the scene */ this.updateResolve = ParamConfig.BUTTON(null, { callback: (node, param) => { NodeCookEventNode.PARAM_CALLBACK_updateResolve(node); } }); /** @param prints the list of nodes the mask resolves to to the console. Useful for debugging */ this.printResolve = ParamConfig.BUTTON(null, { callback: (node, param) => { NodeCookEventNode.PARAM_CALLBACK_printResolve(node); } }); } } const ParamsConfig = new NodeCookEventParamsConfig(); const _NodeCookEventNode = class extends TypedEventNode { constructor() { super(...arguments); this.paramsConfig = ParamsConfig; this._resolvedNodes = []; this._dispatchedFirstNodeCooked = false; this._dispatchedAllNodesCooked = false; this._cookStateByNodeId = /* @__PURE__ */ new Map(); } static type() { return "nodeCook"; } initializeNode() { this.io.inputs.setNamedInputConnectionPoints([ new EventConnectionPoint( _NodeCookEventNode.INPUT_TRIGGER, EventConnectionPointType.BASE, this.processEventTrigger.bind(this) ) ]); this.io.outputs.setNamedOutputConnectionPoints([ new EventConnectionPoint(_NodeCookEventNode.OUTPUT_FIRST_NODE, EventConnectionPointType.BASE), new EventConnectionPoint(_NodeCookEventNode.OUTPUT_EACH_NODE, EventConnectionPointType.BASE), new EventConnectionPoint(_NodeCookEventNode.OUTPUT_ALL_NODES, EventConnectionPointType.BASE) ]); } // for public api // TODO: make it more generic, with input being an enum of input names trigger() { this.processEventTrigger({}); } cook() { this._updateResolvedNodes(); this.cookController.endCook(); } dispose() { super.dispose(); this._reset(); } resolvedNodes() { return this._resolvedNodes; } processEventTrigger(event_context) { this._cookNodesWithMode(); } _cookNodesWithMode() { this._updateResolvedNodes(); const mode = COOK_MODES[this.pv.cookMode]; switch (mode) { case "all together" /* ALL_TOGETHER */: return this._cookNodesAllTogether(); case "batch" /* BATCH */: return this._cookNodesInBatch(); } TypeAssert.unreachable(mode); } _cookNodesAllTogether() { this._cookNodes(this._resolvedNodes); } async _cookNodesInBatch() { const batch_size = this.pv.batchSize; const batches_count = Math.ceil(this._resolvedNodes.length / batch_size); for (let i = 0; i < batches_count; i++) { const start = i * batch_size; const end = (i + 1) * batch_size; const nodes_in_batch = this._resolvedNodes.slice(start, end); await this._cookNodes(nodes_in_batch); } } async _cookNodes(nodes) { const promises = []; for (const node of nodes) { promises.push(this._cookNode(node)); } return await Promise.all(promises); } _cookNode(node) { if (isBooleanTrue(this.pv.force)) { node.setDirty(this); } return node.compute(); } static PARAM_CALLBACK_updateResolvedNodes(node) { node._updateResolvedNodes(); } _updateResolvedNodes() { this._reset(); this._resolvedNodes = this.scene().nodesController.nodesFromMask(this.pv.mask || ""); for (const node of this._resolvedNodes) { node.cookController.registerOnCookEnd(this._callbackNameForNode(node), () => { this._onNodeCookComplete(node); }); this._cookStateByNodeId.set(node.graphNodeId(), false); } } _callbackNameForNode(node) { return `[event/nodeCook] nodeCook=${this.graphNodeId()} target=${node.graphNodeId()}`; } _reset() { this._dispatchedFirstNodeCooked = false; this._cookStateByNodeId.clear(); for (const node of this._resolvedNodes) { node.cookController.deregisterOnCookEnd(this._callbackNameForNode(node)); } this._resolvedNodes = []; } _allNodesHaveCooked() { for (const node of this._resolvedNodes) { const state = this._cookStateByNodeId.get(node.graphNodeId()); if (!state) { return false; } } return true; } _onNodeCookComplete(node) { const registerOnlyFirstCook = isBooleanTrue(this.pv.registerOnlyFirstCooks); const eventContext = { value: { node } }; if (!this._dispatchedFirstNodeCooked || !registerOnlyFirstCook) { this._dispatchedFirstNodeCooked = true; this.dispatchEventToOutput(_NodeCookEventNode.OUTPUT_FIRST_NODE, eventContext); } const nodeHasCooked = this._cookStateByNodeId.get(node.graphNodeId()); if (!nodeHasCooked || !registerOnlyFirstCook) { this.dispatchEventToOutput(_NodeCookEventNode.OUTPUT_EACH_NODE, eventContext); } this._cookStateByNodeId.set(node.graphNodeId(), true); if (!this._dispatchedAllNodesCooked || !registerOnlyFirstCook) { if (this._allNodesHaveCooked()) { this._dispatchedAllNodesCooked = true; this.dispatchEventToOutput(_NodeCookEventNode.OUTPUT_ALL_NODES, {}); } } } static PARAM_CALLBACK_updateResolve(node) { node._updateResolvedNodes(); } static PARAM_CALLBACK_printResolve(node) { node.printResolve(); } printResolve() { console.log(this._resolvedNodes); } }; export let NodeCookEventNode = _NodeCookEventNode; NodeCookEventNode.INPUT_TRIGGER = "trigger"; NodeCookEventNode.OUTPUT_FIRST_NODE = "first"; NodeCookEventNode.OUTPUT_EACH_NODE = "each"; NodeCookEventNode.OUTPUT_ALL_NODES = "all";