@polygonjs/polygonjs
Version:
node-based WebGL 3D engine https://polygonjs.com
398 lines (397 loc) • 13.5 kB
JavaScript
"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);
// }
}