@polygonjs/polygonjs
Version:
node-based WebGL 3D engine https://polygonjs.com
211 lines (210 loc) • 7.02 kB
JavaScript
"use strict";
import { TypedSopNode } from "./_Base";
import { InputCloneMode } from "../../poly/InputCloneMode";
import { NodeParamsConfig, ParamConfig } from "../utils/params/ParamsConfig";
import { SopType } from "../../poly/registers/nodes/types/Sop";
import { ObjectBuilderPersistedConfig } from "../js/code/assemblers/objectBuilder/ObjectBuilderPersistedConfig";
import { AssemblerName } from "../../poly/registers/assemblers/_BaseRegister";
import {
ObjectBuilderAssemblerConstant
} from "../js/code/assemblers/objectBuilder/ObjectBuilderAssemblerCommon";
import { Poly } from "../../Poly";
import { NodeContext } from "../../poly/NodeContext";
import { Group, Object3D } from "three";
import { JsNodeFinder } from "../js/code/utils/NodeFinder";
import { isBoolean, isNumberValid, isColor, isVector } from "../../../core/Type";
import { CoreMask } from "../../../core/geometry/Mask";
const DUMMY = new Object3D();
class ObjectBuilderSopParamsConfig extends NodeParamsConfig {
constructor() {
super(...arguments);
/** @param group to assign the material to */
this.group = ParamConfig.STRING("", {
objectMask: true
});
}
}
const ParamsConfig = new ObjectBuilderSopParamsConfig();
export class ObjectBuilderSopNode extends TypedSopNode {
constructor() {
super(...arguments);
this.paramsConfig = ParamsConfig;
this.persisted_config = new ObjectBuilderPersistedConfig(this);
this._assemblerController = this._createAssemblerController();
this._childrenControllerContext = NodeContext.JS;
this._tmpParent = new Group();
this._objectContainer = { Object3D: DUMMY, objnum: -1 };
this._paramConfigs = [];
this._functionCreationArgs = [];
this._functionEvalArgs = [];
}
static type() {
return SopType.OBJECT_BUILDER;
}
assemblerController() {
return this._assemblerController;
}
usedAssembler() {
return AssemblerName.JS_OBJECT_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 inputObjects = this._getObjects(coreGroup);
for (const inputObject of inputObjects) {
if (inputObject.parent == null) {
this._tmpParent.add(inputObject);
}
}
let objnum = 0;
for (const inputObject of inputObjects) {
this._objectContainer.Object3D = inputObject;
this._objectContainer.objnum = objnum;
evaluator();
inputObject.updateMatrix();
objnum++;
}
const tmpChildren = [...this._tmpParent.children];
for (const inputObject of tmpChildren) {
this._tmpParent.remove(inputObject);
}
this.setCoreGroup(coreGroup);
} else {
this.setObjects([]);
}
}
_getObjects(coreGroup) {
return CoreMask.filterThreejsObjects(coreGroup, this.pv);
}
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;
}
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 = [
ObjectBuilderAssemblerConstant.OBJECT_CONTAINER,
"_setErrorFromError",
...variableNames,
...functionNames,
...paramConfigNames,
wrappedBody
];
this._functionEvalArgs = [
this._objectContainer,
_setErrorFromError,
...variables,
...functions
// 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;
}
}