UNPKG

@polygonjs/polygonjs

Version:

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

388 lines (387 loc) 13.9 kB
"use strict"; import { GlType } from "./../../poly/registers/nodes/types/Gl"; import { TypedGlNode } from "./_Base"; import { GlConnectionPointType, GL_CONNECTION_POINT_TYPES } from "../utils/io/connections/Gl"; import { NodeParamsConfig, ParamConfig } from "../utils/params/ParamsConfig"; import { NetworkChildNodeType, NetworkNodeType, NodeContext } from "../../poly/NodeContext"; import { SubnetOutputGlNode } from "./SubnetOutput"; import { ThreeToGl } from "../../../core/ThreeToGl"; import { rangeStartEnd } from "../../../core/ArrayUtils"; import { TypedNodeTraverser } from "../utils/shaders/NodeTraverser"; import { CodeBuilder } from "./code/utils/CodeBuilder"; import { LineType } from "./code/utils/LineType"; import { FunctionGLDefinition } from "./utils/GLDefinition"; import { CodeFormatter } from "./code/utils/CodeFormatter"; import { ShaderName } from "../utils/shaders/ShaderName"; 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(GL_CONNECTION_POINT_TYPES.indexOf(GlConnectionPointType.FLOAT), { menu: { entries: GL_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 TypedSubnetGlParamsConfigMixin(Base) { return class Mixin extends Base { constructor() { super(...arguments); 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 TypedSubnetGlParamsConfig extends TypedSubnetGlParamsConfigMixin(NodeParamsConfig) { } export class AbstractTypedSubnetGlNode extends TypedGlNode { constructor() { super(...arguments); this._childrenControllerContext = NodeContext.GL; } initializeNode() { var _a; (_a = this.childrenController) == null ? void 0 : _a.setOutputNodeFindMethod(() => { return this.nodesByType(SubnetOutputGlNode.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); } // // // set_lines // // _setLinesPreBlock(shadersCollectionController) { 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 gl_type = connection_point.type(); const out = this.glVarName(connection_point.name()); const in_value = ThreeToGl.any(this.variableForInput(connection_point.name())); const body_line = `${gl_type} ${out} = ${in_value}`; bodyLines.push(body_line); } shadersCollectionController.addBodyLines(this, bodyLines); } setLinesBlockStart(shadersCollectionController) { shadersCollectionController.addBodyLines(this, [`if(true){`]); } setLinesBlockEnd(shadersCollectionController) { shadersCollectionController.addBodyLines(this, ["}"]); } setSubnetInputLines(shadersCollectionController, childNode) { const connections = this.io.connections.inputConnections(); if (!connections) { return; } const bodyLines = []; for (const connection of connections) { if (connection) { const connection_point = connection.destConnectionPoint(); if (connection_point) { const in_value = ThreeToGl.any(this.variableForInput(connection_point.name())); const gl_type = connection_point.type(); const out = childNode.glVarName(connection_point.name()); const body_line = ` ${gl_type} ${out} = ${in_value}`; bodyLines.push(body_line); } } } shadersCollectionController.addBodyLines(childNode, bodyLines, void 0, ADD_BODY_LINES_OPTIONS); } subnetOutputLines(childNode) { const connections = childNode.io.connections.inputConnections(); if (!connections) { return []; } const bodyLines = []; for (const connection of connections) { if (connection) { const connectionPoint = connection.destConnectionPoint(); if (connectionPoint) { const in_value = ThreeToGl.any(childNode.variableForInput(connectionPoint.name())); const out = this.glVarName(connectionPoint.name()); const bodyLine = ` ${out} = ${in_value}`; bodyLines.push(bodyLine); } } } return bodyLines; } setSubnetOutputLines(shadersCollectionController, childNode) { const bodyLines = this.subnetOutputLines(childNode); shadersCollectionController.addBodyLines(childNode, bodyLines, void 0, ADD_BODY_LINES_OPTIONS); } // set_lines_block_end(shadersCollectionController: ShadersCollectionController, childNode: SubnetOutputGlNode) { // shadersCollectionController.addBodyLines(childNode, ['}']); // } setLines(shadersCollectionController) { this._setLinesPreBlock(shadersCollectionController); this.setLinesBlockStart(shadersCollectionController); this._setLinesBlockContent(shadersCollectionController); this.setLinesBlockEnd(shadersCollectionController); } linesBlockContent(shadersCollectionController) { const codeBuilder = this._runCodeBuilder(shadersCollectionController); if (!codeBuilder) { return; } const shadername = shadersCollectionController.currentShaderName(); const bodyLines = codeBuilder.lines(shadername, LineType.BODY); return this._sanitizeBodyLines(bodyLines); } _setLinesBlockContent(shadersCollectionController) { const bodyLines = this.linesBlockContent(shadersCollectionController); if (!bodyLines) { return; } shadersCollectionController.addBodyLines(this, bodyLines, void 0, ADD_BODY_LINES_OPTIONS); } _runCodeBuilder(shadersCollectionController) { const outputNodes = this.nodesByType(NetworkChildNodeType.OUTPUT); const matNode = this.materialNode(); if (!matNode) { return; } if (outputNodes.length == 0) { matNode.states.error.set(`${this.path()}:one output node is required`); } if (outputNodes.length > 1) { matNode.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 = shadersCollectionController.assembler(); const nodeTraverser = new TypedNodeTraverser( this, shadersCollectionController.shaderNames(), (rootNode, shaderName) => { return subnetOutputInputNames; } ); const codeBuilder = new CodeBuilder( nodeTraverser, (shaderName, rootNodes) => { return assembler.rootNodesByShaderName(shaderName, rootNodes); }, assembler ); const paramNodes = []; codeBuilder.buildFromNodes(outputNodes, paramNodes); this._addCodeBuilderDefinition(codeBuilder, shadersCollectionController); return codeBuilder; } _addCodeBuilderDefinition(codeBuilder, shadersCollectionController) { const internalShadersCollectionController = codeBuilder.shadersCollectionController(); if (!internalShadersCollectionController) { return; } const currentShaderName = shadersCollectionController.currentShaderName(); internalShadersCollectionController.setCurrentShaderName(currentShaderName); const shaderNames = shadersCollectionController.shaderNames(); for (const shaderName of shaderNames) { const definitions = []; internalShadersCollectionController.traverseDefinitions(shaderName, (definition) => { const isNotFunction = !(definition instanceof FunctionGLDefinition); const isCurrentShader = shaderName == currentShaderName; if (isNotFunction || isCurrentShader) { definitions.push(definition); } }); shadersCollectionController.addDefinitions(this, definitions, shaderName); } if (currentShaderName != ShaderName.VERTEX) { const attribNodes = this.nodesByType(GlType.ATTRIBUTE); const bodyLines = []; for (const attribNode of attribNodes) { const linesForNode = internalShadersCollectionController.bodyLines(ShaderName.VERTEX, attribNode); if (linesForNode) { bodyLines.push(...linesForNode); } } shadersCollectionController.addBodyLines(this, bodyLines, ShaderName.VERTEX, ADD_BODY_LINES_OPTIONS); } } // align with the right number of tabs _sanitizeBodyLines(lines) { const level = CodeFormatter.nodeDistanceToMaterial(this); const prefix = ` `.repeat(level); return lines.map((line) => { const trimmed = line.trim(); if (trimmed.length == 0) { return ""; } else { return `${prefix}${trimmed}`; } }); } } export class TypedSubnetGlNode extends AbstractTypedSubnetGlNode { 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(GL_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) => GL_CONNECTION_POINT_TYPES[params[i].value]); } _expectedInputName(index) { const params = this._inputNameParams(); const param = params[index]; return param ? param.value : GlConnectionPointType.FLOAT; } _expectedOutputTypes() { const count = this.pv.inputsCount; const params = this._inputTypeParams(); return rangeStartEnd(0, count).map((value, i) => GL_CONNECTION_POINT_TYPES[params[i].value]); } _expectedOutputName(index) { const params = this._inputNameParams(); return params[index].value; } } class SubnetGlParamsConfig extends TypedSubnetGlParamsConfigMixin(NodeParamsConfig) { } const ParamsConfig = new SubnetGlParamsConfig(); export class SubnetGlNode extends TypedSubnetGlNode { constructor() { super(...arguments); this.paramsConfig = ParamsConfig; } static type() { return NetworkNodeType.SUBNET; } }