UNPKG

@polygonjs/polygonjs

Version:

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

297 lines (296 loc) 10.8 kB
"use strict"; import { TypedSopNode } from "./_Base"; import { InputCloneMode } from "../../poly/InputCloneMode"; import { NodeParamsConfig, ParamConfig } from "../utils/params/ParamsConfig"; import { AssemblerName } from "../../poly/registers/assemblers/_BaseRegister"; import { PointBuilderAssemblerConstant } from "../js/code/assemblers/pointBuilder/PointBuilderAssemblerCommon"; import { Poly } from "../../Poly"; import { NodeContext } from "../../poly/NodeContext"; import { createVariable } from "../js/code/assemblers/_BaseJsPersistedConfigUtils"; import { JsNodeFinder } from "../js/code/utils/NodeFinder"; import { isBoolean, isNumberValid, isColor, isVector, isNumber } from "../../../core/Type"; import { BufferAttribute } from "three"; import { JsConnectionPointComponentsCountMap } from "../utils/io/connections/Js"; import { pointsCountFromObject } from "../../../core/geometry/entities/point/CorePointUtils"; import { corePointClassFactory } from "../../../core/geometry/CoreObjectFactory"; import { filterObjectsFromCoreGroup } from "../../../core/geometry/Mask"; export class BasePointBuilderSopParamsConfig extends NodeParamsConfig { constructor() { super(...arguments); /** @param group to assign the material to */ this.group = ParamConfig.STRING("", { objectMask: true }); } } export class BasePointBuilderSopNode extends TypedSopNode { constructor() { super(...arguments); this._assemblerController = this._createAssemblerController(); this._childrenControllerContext = NodeContext.JS; this._paramConfigs = []; this._functionCreationArgs = []; this._functionEvalArgs = []; this._attributesDict = /* @__PURE__ */ new Map(); } assemblerController() { return this._assemblerController; } usedAssembler() { return AssemblerName.JS_POINT_BUILDER; } _createAssemblerController() { return Poly.assemblersRegister.assembler(this, this.usedAssembler()); } createNode(node_class, options) { return super.createNode(node_class, options); } children() { return super.children(); } nodesByType(type) { return super.nodesByType(type); } childrenAllowed() { if (this.assemblerController()) { return super.childrenAllowed(); } return false; } sceneReadonly() { return this.assemblerController() == null; } initializeNode() { this.io.inputs.setCount(1); this.io.inputs.initInputsClonedState(InputCloneMode.FROM_NODE); } async cook(inputCoreGroups) { const coreGroup = inputCoreGroups[0]; this.compileIfRequired(); const _func = this._function; if (_func) { const args = this.functionEvalArgsWithParamConfigs(); const evaluator = _func(...args); const objects = filterObjectsFromCoreGroup(coreGroup, this.pv); let objnum = 0; for (const object of objects) { this._processObject(object, objnum, evaluator); objnum++; } this.setObjects(objects); } else { this.setObjects([]); } } _resetRequiredAttributes() { this._attributesDict.clear(); } _checkRequiredReadAttributes(object) { var _a; const pointsCount = pointsCountFromObject(object); if (pointsCount == 0) { return; } const corePointClass = corePointClassFactory(object); const readAttributesData = (_a = this._functionData) == null ? void 0 : _a.attributesData.read; if (!readAttributesData) { return; } for (const attribData of readAttributesData) { const attribute = corePointClass.attribute(object, attribData.attribName); if (!attribute) { const message = `attribute ${attribData.attribName} is missing`; this.states.error.set(message); throw message; return; } else { const expectedAttribSize = JsConnectionPointComponentsCountMap[attribData.attribType]; if (attribute.itemSize != expectedAttribSize) { this.states.error.set("attribute size mismatch"); } } } const attribNames = []; const attributeByName = /* @__PURE__ */ new Map(); const attribTypeByName = /* @__PURE__ */ new Map(); for (const attribData of readAttributesData) { const attribName = attribData.attribName; const attribute = corePointClass.attribute(object, attribName); if (attribute) { attribNames.push(attribName); attributeByName.set(attribName, attribute); attribTypeByName.set(attribName, attribData.attribType); } } return { attribNames, attributeByName, attribTypeByName }; } _checkRequiredWriteAttributes(object) { var _a; const writeAttributesData = (_a = this._functionData) == null ? void 0 : _a.attributesData.write; if (!writeAttributesData) { return; } const corePointClass = corePointClassFactory(object); for (const attribData of writeAttributesData) { let attribute = corePointClass.attribute(object, attribData.attribName); const expectedAttribSize = JsConnectionPointComponentsCountMap[attribData.attribType]; if (!attribute) { const pointsCount = corePointClass.entitiesCount(object); const newArray = new Array(pointsCount * expectedAttribSize).fill(0); attribute = new BufferAttribute(new Float32Array(newArray), expectedAttribSize); corePointClass.addAttribute(object, attribData.attribName, attribute); } if (attribute.itemSize != expectedAttribSize) { this.states.error.set("attribute size mismatch"); } } const attribNames = []; const attributeByName = /* @__PURE__ */ new Map(); const attribTypeByName = /* @__PURE__ */ new Map(); for (const attribData of writeAttributesData) { const attribName = attribData.attribName; const attribute = corePointClass.attribute(object, attribName); if (attribute) { attribNames.push(attribName); attributeByName.set(attribName, attribute); attribTypeByName.set(attribName, attribData.attribType); } } return { attribNames, attributeByName, attribTypeByName }; } _readRequiredAttributes(ptnum, attribNames, attributeByName, attribTypeByName) { for (const attribName of attribNames) { const attribute = attributeByName.get(attribName); const attribType = attribTypeByName.get(attribName); const variable = createVariable(attribType); if (!variable) { const attribValue = attribute.array[ptnum * attribute.itemSize]; this._attributesDict.set(attribName, attribValue); } else if (isVector(variable) || isColor(variable)) { variable.fromBufferAttribute(attribute, ptnum); this._attributesDict.set(attribName, variable); } } } _writeRequiredAttributes(ptnum, attribNames, attributeByName) { for (const attribName of attribNames) { const attribute = attributeByName.get(attribName); const variable = this._attributesDict.get(attribName); if (isVector(variable) || isColor(variable)) { variable.toArray(attribute.array, ptnum * attribute.itemSize); } else { if (isNumber(variable)) { attribute.array[ptnum] = variable; } } } } compileIfRequired() { var _a; if ((_a = this.assemblerController()) == null ? void 0 : _a.compileRequired()) { this.compile(); } } functionData() { return this._functionData; } compile() { const assemblerController = this.assemblerController(); if (!assemblerController) { return; } const outputNodes = JsNodeFinder.findOutputNodes(this); if (outputNodes.length == 0) { this.states.error.set("one output node is required"); return; } if (outputNodes.length > 1) { this.states.error.set("only one output node allowed"); return; } const outputNode = outputNodes[0]; if (outputNode) { const paramNodes = JsNodeFinder.findParamGeneratingNodes(this); const attributeExportNodes = JsNodeFinder.findAttributeExportNodes(this); const rootNodes = outputNodes.concat(paramNodes).concat(attributeExportNodes); assemblerController.assembler.set_root_nodes(rootNodes); assemblerController.assembler.updateFunction(); const functionData = assemblerController.assembler.functionData(); if (!functionData) { this.states.error.set("failed to compile "); return; } this.updateFromFunctionData(functionData); } assemblerController.post_compile(); } updateFromFunctionData(functionData) { this._functionData = functionData; const { functionBody, variableNames, variablesByName, functionNames, functionsByName, paramConfigs } = this._functionData; const wrappedBody = ` try { ${functionBody} } catch(e) { _setErrorFromError(e) return 0; }`; const _setErrorFromError = (e) => { this.states.error.set(e.message); }; const variables = []; const functions = []; for (const variableName of variableNames) { const variable = variablesByName[variableName]; variables.push(variable); } for (const functionName of functionNames) { const _func = functionsByName[functionName]; functions.push(_func); } this._paramConfigs = [...paramConfigs]; const paramConfigNames = paramConfigs.map((pc) => pc.uniformName()); paramConfigs.forEach((p) => p.applyToNode(this)); this._functionCreationArgs = [ PointBuilderAssemblerConstant.POINT_CONTAINER, "_setErrorFromError", ...variableNames, ...functionNames, PointBuilderAssemblerConstant.ATTRIBUTES_DICT, ...paramConfigNames, wrappedBody ]; this._functionEvalArgs = [ this._pointContainer, _setErrorFromError, ...variables, ...functions, this._attributesDict // paramConfigs are added dynamically during cook ]; try { this._function = new Function(...this._functionCreationArgs); } catch (e) { console.warn(e); this.states.error.set("failed to compile"); } } functionEvalArgsWithParamConfigs() { const list = [...this._functionEvalArgs]; for (const paramConfig of this._paramConfigs) { const paramName = paramConfig.name(); const spareParam = this.params.get(paramName); if (spareParam && spareParam.value != null) { if (isBoolean(spareParam.value) || isNumberValid(spareParam.value) || isColor(spareParam.value) || isVector(spareParam.value)) { list.push(spareParam.value); } else { console.warn(`spareParam not found but type not yet copied to function args:'${paramName}'`); } } else { console.warn(`spareParam not found:'${paramName}'`); } } return list; } }