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