UNPKG

@polygonjs/polygonjs

Version:

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

180 lines (165 loc) 6.11 kB
import { BaseJsShaderAssembler, INSERT_DEFINE_AFTER, INSERT_BODY_AFTER, INSERT_MEMBERS_AFTER, INSERT_CONSTRUCTOR_AFTER, SpareParamOptions, } from '../_Base'; import {RegisterableVariable} from '../_BaseJsPersistedConfigUtils'; import {JsFunctionName} from '../../../../utils/shaders/ShaderName'; import {JsLinesCollectionController} from '../../utils/JsLinesCollectionController'; import {NamedFunctionMap} from '../../../../../poly/registers/functions/All'; import {ParamOptions} from '../../../../../params/utils/OptionsController'; import {AttributeJsNodeInput} from '../../../Attribute'; import {NodeContext} from '../../../../../poly/NodeContext'; import {JsType} from '../../../../../poly/registers/nodes/types/Js'; import { EntityBuilderFunctionData, EntityBuilderFunctionDataAttributeDataItem, } from './_BaseEntityBuilderPersistedConfig'; import {PrettierController} from '../../../../../../core/code/PrettierController'; import {EntityBuilderAssemblerConstant} from './EntityBuilderAssemblerCommon'; import type {AttributeJsNode} from '../../../Attribute'; const TEMPLATE = ` ${INSERT_DEFINE_AFTER} ${INSERT_MEMBERS_AFTER} ${INSERT_CONSTRUCTOR_AFTER} const __EVALUATOR_NAME___ = function(){ ${INSERT_BODY_AFTER} `; const CLOSE_CLASS_DEFINITION = `}; return __EVALUATOR_NAME___;`; export class JsAssemblerBaseEntityBuilder extends BaseJsShaderAssembler { makeFunctionNodeDirtyOnChange() { return true; } override templateShader() { return { main: TEMPLATE.replace(/__EVALUATOR_NAME___/g, this._evaluatorName()), }; } protected _closeClassDefinition() { return CLOSE_CLASS_DEFINITION.replace(/__EVALUATOR_NAME___/g, this._evaluatorName()); } protected _evaluatorName(): string { return 'BaseEntityBuilderEvaluator'; } override spareParamsOptions(options: SpareParamOptions) { const _options: ParamOptions = { spare: true, // computeOnDirty: true, // not needed if cook option is not set // cook: false, // for SDFBuilder, the node needs to recook // important for texture nodes // that compute after being found by the nodepath param dependentOnFoundNode: true, }; return _options; } defaultObjectVariable(): string { return EntityBuilderAssemblerConstant.OBJECT; } defaultObject3DMaterialVariable(): string { return EntityBuilderAssemblerConstant.MATERIAL; } defaultPrimitiveGraph():string { return EntityBuilderAssemblerConstant.PRIMITIVE_GRAPH; } functionData(): EntityBuilderFunctionData | undefined { // const functionBody = this._shaders_by_name.get(ShaderName.FRAGMENT); const _buildFunctionBody = () => { const bodyLines = this._shaders_by_name.get(JsFunctionName.MAIN) || TEMPLATE; const functionBodyElements = [ bodyLines, // triggerableFunctionLines.join('\n'), // triggerFunctionLines.join('\n'), this._closeClassDefinition(), ]; const functionBody = PrettierController.formatJs(functionBodyElements.join('\n')); return functionBody; }; const functionBody = _buildFunctionBody(); if (!functionBody) { return; } const variableNames: string[] = []; const functionNames: Array<keyof NamedFunctionMap> = []; const variablesByName: Record<string, RegisterableVariable> = {}; const functionsByName: Record<string, Function> = {}; this.traverseRegisteredVariables((variable, varName) => { variableNames.push(varName); variablesByName[varName] = variable; }); this.traverseRegisteredFunctions((namedFunction) => { functionNames.push(namedFunction.type() as keyof NamedFunctionMap); functionsByName[namedFunction.type()] = namedFunction.func.bind(namedFunction); }); // gather attribute data const attribNodes: AttributeJsNode[] = []; this.currentJsParentNode().childrenController?.traverseChildren((child) => { if (child.context() == NodeContext.JS && child.type() == JsType.ATTRIBUTE) { attribNodes.push(child as AttributeJsNode); } }); const attributesRead: EntityBuilderFunctionDataAttributeDataItem[] = attribNodes .filter((n) => n.isImporting()) .map((attribNode) => attribNode.attribData()); const attributesWrite: EntityBuilderFunctionDataAttributeDataItem[] = attribNodes .filter((n) => n.isExporting()) .map((attribNode) => attribNode.attribData()); // const paramConfigs = this.param_configs(); const paramConfigs = this.param_configs(); return { functionBody, variableNames, variablesByName, functionNames, functionsByName, paramConfigs: [...paramConfigs], attributesData: { read: attributesRead, write: attributesWrite, }, }; } override updateFunction() { super.updateFunction(); this._lines = new Map(); this._shaders_by_name = new Map(); const shaderNames = this.shaderNames(); if (this._root_nodes.length > 0) { this.buildCodeFromNodes(this._root_nodes); this._buildLines(); } for (const shaderName of shaderNames) { const lines = this._lines.get(shaderName); if (lines) { this._shaders_by_name.set(shaderName, lines.join('\n')); } } } override setNodeLinesAttribute(attributeNode: AttributeJsNode, linesController: JsLinesCollectionController) { const shaderName = linesController.currentShaderName(); const shaderConfig = this.shader_config(shaderName); if (!shaderConfig) { return; } const bodyLines: string[] = []; const attribName = attributeNode.attributeName(); // const dataType = attributeNode.jsType(); // export if (attributeNode.isExporting()) { const exportedValue = attributeNode.variableForInput(linesController, AttributeJsNodeInput.EXPORT); const bodyLine = `${EntityBuilderAssemblerConstant.ATTRIBUTES_DICT}.set('${attribName}', ${exportedValue})`; bodyLines.push(bodyLine); } // output const usedOutputNames = attributeNode.io.outputs.used_output_names(); for (const outputName of usedOutputNames) { const varName = attributeNode.jsVarName(outputName); const bodyLine = `${varName} = ${EntityBuilderAssemblerConstant.ATTRIBUTES_DICT}.get('${attribName}')`; bodyLines.push(bodyLine); } linesController._addBodyLines(attributeNode, bodyLines); } }