@polygonjs/polygonjs
Version:
node-based WebGL 3D engine https://polygonjs.com
166 lines (165 loc) • 6.27 kB
JavaScript
"use strict";
import { JsNodeFinder } from "../../engine/nodes/js/code/utils/NodeFinder";
import { ActorEvaluator } from "../../engine/nodes/js/code/assemblers/actor/ActorEvaluator";
import { ActorEvaluatorGenerator } from "../../engine/nodes/js/code/assemblers/actor/ActorEvaluatorGenerator";
import { computed, ref, watch } from "../reactivity/CoreReactivity";
import { Object3D } from "three";
import { FUNC_POINTS_COUNT_FROM_OBJECT, FUNC_CORE_PRIMITIVE_CLASS_FACTORY } from "../../engine/nodes/js/utils/Common";
import { pointsCountFromObject } from "../geometry/entities/point/CorePointUtils";
import { corePrimitiveClassFactory } from "../geometry/CoreObjectFactory";
import { arrayToSet } from "../ArrayUtils";
const FUNCTION_ARGS_DICT = {
[FUNC_POINTS_COUNT_FROM_OBJECT]: pointsCountFromObject,
[FUNC_CORE_PRIMITIVE_CLASS_FACTORY]: corePrimitiveClassFactory,
ActorEvaluator,
computed,
ref,
watch
};
const FUNCTION_ARG_NAMES = Object.keys(FUNCTION_ARGS_DICT);
const FUNCTION_ARGS = FUNCTION_ARG_NAMES.map((argName) => FUNCTION_ARGS_DICT[argName]);
export const ACTOR_COMPILATION_CONTROLLER_DUMMY_OBJECT_NAME = "ActorCompilationController-DUMMY";
function _createDummyObject() {
const object = new Object3D();
object.name = ACTOR_COMPILATION_CONTROLLER_DUMMY_OBJECT_NAME;
return object;
}
export const ACTOR_COMPILATION_CONTROLLER_DUMMY_OBJECT = _createDummyObject();
export class ActorCompilationController {
constructor(node) {
this.node = node;
this._evaluatorGenerator = new ActorEvaluatorGenerator(
(object) => new ActorEvaluator(this.node, object)
);
}
compileIfRequired() {
var _a;
if ((_a = this.node.assemblerController()) == null ? void 0 : _a.compileRequired()) {
this.compile();
}
this._evaluatorGenerator.clearObjects();
}
evaluatorGenerator() {
return this._evaluatorGenerator;
}
functionData() {
return this._functionData;
}
_resetFunctionData() {
this._functionData = void 0;
}
updateFromFunctionData(functionData) {
this._functionData = functionData;
const { functionBody, variableNames, variablesByName, functionNames, functionsByName, paramConfigs, eventDatas } = this._functionData;
const wrappedBody = `
try {
${functionBody}
} catch(e) {
console.log(e);
_setErrorFromError(e)
return null
}`;
const _setErrorFromError = (e) => {
this.node.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);
}
const paramConfigUniformNames = paramConfigs.map((pc) => pc.uniformName());
paramConfigs.forEach((p) => p.applyToNode(this.node));
const functionCreationArgs = [
...FUNCTION_ARG_NAMES,
"_setErrorFromError",
...variableNames,
...functionNames,
// ...FUNCTION_UTILS.names,
...paramConfigUniformNames,
wrappedBody
];
const functionEvalArgs = () => [
...FUNCTION_ARGS,
_setErrorFromError,
// it is currently preferable to create a unique set of variables
// for each evaluator
...variables.map((v) => v.clone()),
...functions
// ...FUNCTION_UTILS.functions,
];
try {
const _function = new Function(...functionCreationArgs);
const _createEvaluator = (object) => {
const evaluatorClass = _function(...functionEvalArgs());
const evaluator = new evaluatorClass(this.node, object);
return evaluator;
};
const evaluatorGenerator = new ActorEvaluatorGenerator((object) => {
const evaluator = _createEvaluator(object);
return this.node.scene().dispatchController.processActorEvaluator(evaluator) || evaluator;
});
const dummyEvaluator = _createEvaluator(ACTOR_COMPILATION_CONTROLLER_DUMMY_OBJECT);
evaluatorGenerator.setExpectedEvaluatorMethodNames(dummyEvaluator);
evaluatorGenerator.eventDatas = evaluatorGenerator.eventDatas || /* @__PURE__ */ new Set();
arrayToSet(eventDatas, evaluatorGenerator.eventDatas);
this._setEvaluatorGenerator(evaluatorGenerator);
} catch (e) {
console.warn(e);
console.log(`failed to compile actor node ${this.node.path()}`);
console.log({ functionData });
this.node.states.error.set("failed to compile");
}
}
_setEvaluatorGenerator(evaluatorGenerator) {
this.node.scene().actorsManager.unregisterEvaluatorGenerator(this._evaluatorGenerator);
this._evaluatorGenerator.clearObjects();
this._evaluatorGenerator = evaluatorGenerator;
this.node.scene().actorsManager.registerEvaluatorGenerator(evaluatorGenerator);
}
compile() {
const assemblerController = this.node.assemblerController();
if (!assemblerController) {
return;
}
this.node.states.error.clear();
assemblerController.assembler.updateFunction();
const paramNodes = JsNodeFinder.findParamGeneratingNodes(this.node);
try {
const functionData = assemblerController.assembler.createFunctionData(paramNodes);
if (!functionData) {
this._resetFunctionData();
return;
}
this.updateFromFunctionData(functionData);
assemblerController.post_compile();
} catch (err) {
console.log(err);
this._resetFunctionData();
}
this._runOnCompilationCompletedCallbacks();
}
addOnCompilationCompleted(callback) {
this._onCompilationCompletedCallbacks = this._onCompilationCompletedCallbacks || /* @__PURE__ */ new Set();
this._onCompilationCompletedCallbacks.add(callback);
}
removeOnCompilationCompleted(callback) {
if (!this._onCompilationCompletedCallbacks) {
return;
}
this._onCompilationCompletedCallbacks.delete(callback);
if (this._onCompilationCompletedCallbacks.size == 0) {
this._onCompilationCompletedCallbacks = void 0;
}
}
_runOnCompilationCompletedCallbacks() {
if (!this._onCompilationCompletedCallbacks) {
return;
}
this._onCompilationCompletedCallbacks.forEach((callback) => callback());
}
}