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