UNPKG

@polygonjs/polygonjs

Version:

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

398 lines (397 loc) 13.5 kB
"use strict"; import { TypedJsNode } from "./_Base"; import { JsConnectionPointType, JS_CONNECTION_POINT_TYPES } from "../utils/io/connections/Js"; import { NodeParamsConfig, ParamConfig } from "../utils/params/ParamsConfig"; import { NetworkChildNodeType, NetworkNodeType, NodeContext } from "../../poly/NodeContext"; import { SubnetOutputJsNode } from "./SubnetOutput"; import { rangeStartEnd } from "../../../core/ArrayUtils"; import { LineType } from "./code/utils/LineType"; import { TypedNodeTraverser } from "../utils/shaders/NodeTraverser"; import { JsCodeBuilder } from "./code/utils/CodeBuilder"; export const ADD_BODY_LINES_OPTIONS = { makeUniq: false }; function visibleIfInputsCountAtLeast(index) { return { visibleIf: rangeStartEnd(index + 1, 10).map((i) => ({ inputsCount: i })) }; } function inputTypeParam(index) { return ParamConfig.INTEGER(JS_CONNECTION_POINT_TYPES.indexOf(JsConnectionPointType.FLOAT), { menu: { entries: JS_CONNECTION_POINT_TYPES.map((name, i) => { return { name, value: i }; }) }, separatorBefore: true, ...visibleIfInputsCountAtLeast(index) }); } function inputNameParam(index) { return ParamConfig.STRING(`input${index}`, { ...visibleIfInputsCountAtLeast(index) }); } export function TypedSubnetJsParamsConfigMixin(Base) { return class Mixin extends Base { constructor() { super(...arguments); this.main = ParamConfig.FOLDER(); this.time = ParamConfig.FLOAT(0, { step: 1e-3 }); this.inputs = ParamConfig.FOLDER(); this.inputsCount = ParamConfig.INTEGER(1, { range: [0, 10], rangeLocked: [true, true] }); this.inputType0 = inputTypeParam(0); this.inputName0 = inputNameParam(0); this.inputType1 = inputTypeParam(1); this.inputName1 = inputNameParam(1); this.inputType2 = inputTypeParam(2); this.inputName2 = inputNameParam(2); this.inputType3 = inputTypeParam(3); this.inputName3 = inputNameParam(3); this.inputType4 = inputTypeParam(4); this.inputName4 = inputNameParam(4); this.inputType5 = inputTypeParam(5); this.inputName5 = inputNameParam(5); this.inputType6 = inputTypeParam(6); this.inputName6 = inputNameParam(6); this.inputType7 = inputTypeParam(7); this.inputName7 = inputNameParam(7); this.inputType8 = inputTypeParam(8); this.inputName8 = inputNameParam(8); this.inputType9 = inputTypeParam(9); this.inputName9 = inputNameParam(9); this.spare = ParamConfig.FOLDER(); } }; } class TypedSubnetJsParamsConfig extends TypedSubnetJsParamsConfigMixin(NodeParamsConfig) { } export class AbstractTypedSubnetJsNode extends TypedJsNode { constructor() { super(...arguments); this._childrenControllerContext = NodeContext.JS; } initializeNode() { var _a; (_a = this.childrenController) == null ? void 0 : _a.setOutputNodeFindMethod(() => { return this.nodesByType(SubnetOutputJsNode.type())[0]; }); this.io.connection_points.set_input_name_function(this._expectedInputName.bind(this)); this.io.connection_points.set_expected_input_types_function(this._expectedInputTypes.bind(this)); this.io.connection_points.set_expected_output_types_function(this._expectedOutputTypes.bind(this)); this.io.connection_points.set_output_name_function(this._expectedOutputName.bind(this)); } _expectedInputTypes() { return []; } _expectedInputName(index) { return "default"; } _expectedOutputTypes() { return this._expectedInputTypes(); } _expectedOutputName(index) { return this._expectedInputName(index); } // // // defines the outputs for the child subnet input // // childExpectedInputConnectionPointTypes() { return this._expectedInputTypes(); } childExpectedOutputConnectionPointTypes() { return this._expectedOutputTypes(); } childExpectedInputConnectionPointName(index) { return this._expectedInputName(index); } childExpectedOutputConnectionPointName(index) { return this._expectedOutputName(index); } createNode(node_class, options) { return super.createNode(node_class, options); } children() { return super.children(); } nodesByType(type) { return super.nodesByType(type); } } export class TypedSubnetJsNode extends AbstractTypedSubnetJsNode { initializeNode() { super.initializeNode(); this.io.connection_points.set_input_name_function(this._expectedInputName.bind(this)); this.io.connection_points.set_expected_input_types_function(this._expectedInputTypes.bind(this)); this.io.connection_points.set_expected_output_types_function(this._expectedOutputTypes.bind(this)); this.io.connection_points.set_output_name_function(this._expectedOutputName.bind(this)); } _inputTypeParams() { return [ this.p.inputType0, this.p.inputType1, this.p.inputType2, this.p.inputType3, this.p.inputType4, this.p.inputType5, this.p.inputType6, this.p.inputType7, this.p.inputType8, this.p.inputType9 ]; } _inputNameParams() { return [ this.p.inputName0, this.p.inputName1, this.p.inputName2, this.p.inputName3, this.p.inputName4, this.p.inputName5, this.p.inputName6, this.p.inputName7, this.p.inputName8, this.p.inputName9 ]; } setInputType(index, type) { const param = this._inputTypeParams()[index]; if (!param) { return; } param.set(JS_CONNECTION_POINT_TYPES.indexOf(type)); } setInputName(index, inputName) { const param = this._inputNameParams()[index]; if (!param) { return; } param.set(inputName); } _expectedInputsCount() { return this.pv.inputsCount; } _expectedInputTypes() { const count = this.pv.inputsCount; const params = this._inputTypeParams(); return rangeStartEnd(0, count).map((value, i) => JS_CONNECTION_POINT_TYPES[params[i].value]); } _expectedInputName(index) { const params = this._inputNameParams(); const param = params[index]; return param ? param.value : JsConnectionPointType.FLOAT; } _expectedOutputTypes() { const count = this.pv.inputsCount; const params = this._inputTypeParams(); return rangeStartEnd(0, count).map((value, i) => JS_CONNECTION_POINT_TYPES[params[i].value]); } _expectedOutputName(index) { const params = this._inputNameParams(); return params[index].value; } setLines(linesController) { this._setLinesPreBlock(linesController); this.setLinesBlockStart(linesController); this._setLinesBlockContent(linesController); this.setLinesBlockEnd(linesController); } linesBlockContent(linesController) { const codeBuilder = this._runCodeBuilder(linesController); if (!codeBuilder) { return; } const shadername = linesController.currentShaderName(); const bodyLines = codeBuilder.lines(shadername, LineType.BODY); return this._sanitizeBodyLines(bodyLines); } _setLinesPreBlock(linesController) { if (this._traverseChildren(linesController)) { return; } const bodyLines = []; const connection_points = this.io.inputs.namedInputConnectionPoints(); if (!connection_points) { return; } for (let i = 0; i < connection_points.length; i++) { const connection_point = connection_points[i]; const out = this.jsVarName(connection_point.name()); const in_value = this.variableForInput(linesController, connection_point.name()); const body_line = `let ${out} = ${in_value}`; bodyLines.push(body_line); } linesController._addBodyLines(this, bodyLines); } setLinesBlockStart(linesController) { if (this._traverseChildren(linesController)) { return; } linesController._addBodyLines(this, [`if(true){`]); } _setLinesBlockContent(linesController) { const bodyLines = this.linesBlockContent(linesController); if (!bodyLines) { return; } linesController._addBodyLines(this, bodyLines, void 0, ADD_BODY_LINES_OPTIONS); } setLinesBlockEnd(linesController) { if (this._traverseChildren(linesController)) { return; } linesController._addBodyLines(this, [`}`]); } _runCodeBuilder(linesController) { const outputNodes = this.nodesByType(NetworkChildNodeType.OUTPUT); const functionNode = this.functionNode(); if (!functionNode) { return; } if (outputNodes.length == 0) { functionNode.states.error.set(`${this.path()}:one output node is required`); } if (outputNodes.length > 1) { functionNode.states.error.set(`${this.path()}:only one output node allowed`); } const subnetOutput = outputNodes[0]; const subnetOutputInputConnectionPoints = subnetOutput.io.inputs.namedInputConnectionPoints(); const subnetOutputInputNames = subnetOutputInputConnectionPoints ? subnetOutputInputConnectionPoints.map((cp) => cp.name()) : []; const assembler = linesController.assembler(); const nodeTraverser = new TypedNodeTraverser( this, linesController.shaderNames(), (rootNode, shaderName) => { return subnetOutputInputNames; } ); const codeBuilder = new JsCodeBuilder( nodeTraverser, (shaderName, rootNodes) => { return assembler.rootNodesByShaderName(shaderName, rootNodes); }, assembler ); const paramNodes = []; codeBuilder.buildFromNodes(outputNodes, paramNodes); this._addCodeBuilderDefinition(codeBuilder, linesController); return codeBuilder; } _addCodeBuilderDefinition(codeBuilder, linesController) { const internalShadersCollectionController = codeBuilder.shadersCollectionController(); if (!internalShadersCollectionController) { return; } const currentShaderName = linesController.currentShaderName(); internalShadersCollectionController.setCurrentShaderName(currentShaderName); const shaderNames = linesController.shaderNames(); for (const shaderName of shaderNames) { const definitions = []; internalShadersCollectionController.traverseDefinitions(shaderName, (definition) => { const isNotFunction = true; //!(definition instanceof FunctionGLDefinition); const isCurrentShader = shaderName == currentShaderName; if (isNotFunction || isCurrentShader) { definitions.push(definition); } }); linesController.addDefinitions(this, definitions, shaderName); } } setSubnetInputLines(linesController, childNode) { const outputTypes = childNode.expectedOutputTypes(); let i = 0; for (const _ of outputTypes) { const inputName = this.inputNameForSubnetInput(i); const inputValue = this.variableForInput(linesController, inputName); const dataType = outputTypes[0]; const varName = childNode.jsVarName(inputName); linesController.addBodyOrComputed(childNode, [ { dataType, varName, value: inputValue } ]); i++; } } setSubnetOutputLines(linesController, childNode) { const inputTypes = childNode.expectedInputTypes(); let i = 0; const addLineIfNotConnected = this._traverseChildren(linesController); for (const _ of inputTypes) { const inputName = childNode.expectedInputName(i); const inputValue = childNode.variableForInput(linesController, inputName); const dataType = inputTypes[0]; const varName = this.jsVarName(this.outputNameForSubnetOutput(i) || ""); const isInputConnected = childNode.io.inputs.named_input(inputName); const addLine = isInputConnected || addLineIfNotConnected; if (addLine) { linesController.addBodyOrComputed( childNode, [ { dataType, varName, value: inputValue } ], { constPrefix: false } ); } i++; } } _traverseChildren(linesController) { return linesController.assembler().computedVariablesAllowed(); } inputNameForSubnetInput(index) { return this._expectedInputName(index); } outputNameForSubnetOutput(index) { return this._expectedOutputName(index); } // align with the right number of tabs _sanitizeBodyLines(lines) { return lines; } } class SubnetJsParamsConfig extends TypedSubnetJsParamsConfigMixin(NodeParamsConfig) { } const ParamsConfig = new SubnetJsParamsConfig(); export class SubnetJsNode extends TypedSubnetJsNode { constructor() { super(...arguments); this.paramsConfig = ParamsConfig; } static type() { return NetworkNodeType.SUBNET; } // public override outputValue(context: JsNodeTriggerContext, outputName: string) { // const subnetOutput = this.nodesByType(NetworkChildNodeType.OUTPUT)[0]; // if (subnetOutput) { // return subnetOutput.outputValue(context, outputName); // } else { // return 0; // } // } // inputValueForSubnetInput(context: JsNodeTriggerContext, outputName: string) { // return this._inputValue<JsConnectionPointType>(outputName, context) || 0; // } // override inputNameForSubnetInput(index: number) { // return this._expectedInputName(index); // } // override outputNameForSubnetOutput(index: number) { // return this._expectedOutputName(index); // } }