UNPKG

@polygonjs/polygonjs

Version:

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

463 lines (462 loc) 14.9 kB
"use strict"; import { CoreGraphNode } from "../../../../core/graph/CoreGraphNode"; import { ParamType } from "../../../poly/ParamType"; import { ParamConstructorByType } from "../../../params/types/ParamConstructorByType"; import { NodeEvent } from "../../../poly/NodeEvent"; import { Poly } from "../../../Poly"; import { arrayCopy } from "../../../../core/ArrayUtils"; const NODE_SIMPLE_NAME = "params"; const _tmpAll = []; export class ParamsController { constructor(node) { this.node = node; this._param_create_mode = false; this._params_created = false; this._paramsByName = /* @__PURE__ */ new Map(); // caches this._paramsList = []; this._paramNames = []; this._non_spare_params = []; this._spare_params = []; this._non_spare_param_names = []; this._spare_param_names = []; // private _params_eval_key: string; this._params_added_since_last_params_eval = false; this._promises = []; } dispose() { if (this._params_node) { this._params_node.dispose(); } arrayCopy(this.all, _tmpAll); for (const param of _tmpAll) { param.dispose(); } this._post_create_params_hook_names = void 0; this._post_create_params_hooks = void 0; this._on_scene_load_hooks = void 0; this._on_scene_load_hook_names = void 0; } initDependencyNode() { if (!this._params_node) { this._params_node = new CoreGraphNode(this.node.scene(), NODE_SIMPLE_NAME); this.node.addGraphInput(this._params_node, false); } } init() { this.initDependencyNode(); this._param_create_mode = true; this._initFromParamsConfig(); this.node.createParams(); this._postCreateParams(); } _postCreateParams() { this._updateCaches(); this._initParamAccessors(); this._param_create_mode = false; this._params_created = true; this._runPostCreateParamsHooks(); } postCreateSpareParams() { this._updateCaches(); this._initParamAccessors(); this.node.scene().referencesController.notifyParamsUpdated(this.node); this.node.emit(NodeEvent.PARAMS_UPDATED); } updateParams(options) { let hasCreatedAParam = false; let hasDeletedAParam = false; const addedParams = []; if (options.namesToDelete) { for (const param_name of options.namesToDelete) { if (this.has(param_name)) { this._deleteParam(param_name); hasDeletedAParam = true; } } } if (options.toAdd) { for (const paramData of options.toAdd) { const param = this.addParam(paramData.type, paramData.name, paramData.initValue, paramData.options); if (param) { if (paramData.rawInput != null) { param.set(paramData.rawInput); } hasCreatedAParam = true; addedParams.push(param); } } } if (hasDeletedAParam || hasCreatedAParam) { this.postCreateSpareParams(); } for (const param of addedParams) { this.node.scene().missingExpressionReferencesController.checkForMissingParamReferences(param); } } _initFromParamsConfig() { var _a; const paramsConfig = this.node.paramsConfig; let init_values_used = false; if (paramsConfig) { const paramsInitValueOverrides = (_a = this.node.createOptions) == null ? void 0 : _a.paramsInitValueOverrides; const names = Object.keys(paramsConfig); for (const name of names) { const config = paramsConfig[name]; let init_value; if (paramsInitValueOverrides) { init_value = paramsInitValueOverrides[name]; init_values_used = true; } this.addParam(config.type, name, config.init_value, config.options, init_value); } } if (init_values_used) { this.node.setDirty(); } if (this.node.createOptions) { this.node.createOptions.paramsInitValueOverrides = void 0; } } _initParamAccessors() { let currentNamesInAccessor = Object.getOwnPropertyNames(this.node.pv); this._removeUnneededAccessors(currentNamesInAccessor); currentNamesInAccessor = Object.getOwnPropertyNames(this.node.pv); const all = this.all; for (const param of all) { const isSpare = param.options.isSpare(); const paramNotYetInAccessors = !currentNamesInAccessor.includes(param.name()); try { if (paramNotYetInAccessors || isSpare) { Object.defineProperty(this.node.pv, param.name(), { get: () => { return param.value; }, // only spare parameters can be removed configurable: isSpare }); Object.defineProperty(this.node.p, param.name(), { get: () => { return param; }, configurable: isSpare }); } } catch (err) { } } } _removeUnneededAccessors(current_names_in_accessor) { const current_param_names = this._paramNames; const names_to_remove = []; for (const current_name_in_accessor of current_names_in_accessor) { if (!current_param_names.includes(current_name_in_accessor)) { names_to_remove.push(current_name_in_accessor); } } for (const name_to_remove of names_to_remove) { Object.defineProperty(this.node.pv, name_to_remove, { get: () => { return void 0; }, configurable: true }); Object.defineProperty(this.node.p, name_to_remove, { get: () => { return void 0; }, configurable: true }); } } get params_node() { return this._params_node; } get all() { return this._paramsList; } get non_spare() { return this._non_spare_params; } get spare() { return this._spare_params; } get names() { return this._paramNames; } get non_spare_names() { return this._non_spare_param_names; } get spare_names() { return this._spare_param_names; } set_with_type(paramName, value, type) { const param = this.paramWithType(paramName, type); if (param) { param.set(value); } else { Poly.warn(`param ${paramName} not found with type ${type}`); } } set_float(paramName, value) { this.set_with_type(paramName, value, ParamType.FLOAT); } set_vector3(paramName, value) { this.set_with_type(paramName, value, ParamType.VECTOR3); } has_param(paramName) { return this._paramsByName.has(paramName); } has(paramName) { return this.has_param(paramName); } get(paramName) { return this.param(paramName); } paramWithType(param_name, type) { const param = this.param(param_name); if (param && param.type() == type) { return param; } } getFloat(param_name) { return this.paramWithType(param_name, ParamType.FLOAT); } // get_operator_path(param_name: string): OperatorPathParam { // return this.paramWithType(param_name, ParamType.OPERATOR_PATH) as OperatorPathParam; // } value(paramName) { var _a; return (_a = this.param(paramName)) == null ? void 0 : _a.value; } valueWithType(paramName, type) { var _a; return (_a = this.paramWithType(paramName, type)) == null ? void 0 : _a.value; } boolean(paramName) { return this.valueWithType(paramName, ParamType.BOOLEAN); } float(paramName) { return this.valueWithType(paramName, ParamType.FLOAT); } integer(paramName) { return this.valueWithType(paramName, ParamType.INTEGER); } string(paramName) { return this.valueWithType(paramName, ParamType.STRING); } vector2(paramName) { return this.valueWithType(paramName, ParamType.VECTOR2); } vector3(paramName) { return this.valueWithType(paramName, ParamType.VECTOR3); } color(paramName) { return this.valueWithType(paramName, ParamType.COLOR); } param(paramName) { const p = this._paramsByName.get(paramName); if (p != null) { return p; } else { Poly.warn( `tried to access param '${paramName}' in node ${this.node.path()}, but existing params are: ${this.names} on node ${this.node.path()}` ); return null; } } // param_cache_name(param_name: string) { // return `_param_${param_name}`; // } // delete_params(param_names: string[]) { // for (let param_name of param_names) { // this.delete_param(param_name); // } // } // call update_params instead _deleteParam(paramName) { const param = this._paramsByName.get(paramName); if (param) { if (this._params_node) { this._params_node.removeGraphInput(param); } param._setupNodeDependencies(null); this._paramsByName.delete(paramName); if (param.isMultiple() && param.components) { for (const component of param.components) { const childName = component.name(); this._paramsByName.delete(childName); } } param.dispose(); param.scene().graphNodesController.notifyParamPathChanged(param); } else { throw new Error(`param '${paramName}' does not exist on node ${this.node.path()}`); } } addParam(type, paramName, defaultValue, options = {}, initData) { const isSpare = options["spare"] || false; if (this._param_create_mode === false && !isSpare) { Poly.warn( `node ${this.node.path()} (${this.node.type()}) param '${paramName}' cannot be created outside of createParams` ); } if (this.node.scene() == null) { Poly.warn(`node ${this.node.path()} (${this.node.type()}) has no scene assigned`); } const constructor = ParamConstructorByType[type]; if (constructor != null) { const existing_param = this._paramsByName.get(paramName); if (existing_param) { if (isSpare) { if (existing_param.type() != type) { this._deleteParam(existing_param.name()); } } else { Poly.warn(`a param named ${paramName} already exists`, this.node); } } const param = new constructor(this.node.scene(), this.node, { serializerClass: this.node.scene().paramSerializerClass() }); param.options.set(options); param.setName(paramName); param.setInitValue(defaultValue); param.initComponents(); if (initData == null) { param.set(defaultValue); } else { if (param.options.isExpressionForEntities()) { param.set(defaultValue); } if (initData.raw_input != null) { param.set(initData.raw_input); } else { if (initData.simple_data != null) { param.set(initData.simple_data); } else { if (initData.complex_data != null) { const raw_input = initData.complex_data.raw_input; if (raw_input) { param.set(raw_input); } else { param.set(defaultValue); } const overriden_options = initData.complex_data.overriden_options; if (overriden_options != null) { const keys = Object.keys(overriden_options); for (const key of keys) { param.options.setOption(key, overriden_options[key]); } } } } } } param.postOptionsInitialize(); param._setupNodeDependencies(this.node); this._paramsByName.set(param.name(), param); if (param.isMultiple() && param.components) { for (const component of param.components) { this._paramsByName.set(component.name(), component); } } this._params_added_since_last_params_eval = true; param.scene().graphNodesController.notifyParamPathChanged(param); return param; } } _updateCaches() { this._paramsList.splice(0, this._paramsList.length); this._paramsByName.forEach((param) => { this._paramsList.push(param); }); this._paramNames = this._paramsList.map((param) => param.name()); this._non_spare_params = this._paramsList.filter((p) => !p.options.isSpare()); this._spare_params = this._paramsList.filter((p) => p.options.isSpare()); this._non_spare_param_names = this._non_spare_params.map((p) => p.name()); this._spare_param_names = this._spare_params.map((p) => p.name()); } async _evalParam(param) { if (param.isDirty()) { await param.compute(); if (param.states.error.active() && param.disposed() == false) { this.node.states.error.set(`param '${param.name()}' error: ${param.states.error.message()}`); } } } async evalParams(params) { let dirtyParamsCount = 0; for (const param of params) { if (param.isDirty()) { dirtyParamsCount += 1; } } this._promises.length = dirtyParamsCount; let i = 0; for (const param of params) { if (param.isDirty()) { this._promises[i] = this._evalParam(param); i += 1; } } await Promise.all(this._promises); if (this.node.states.error.active()) { this.node._setContainer(null); } } paramsEvalRequired() { return this._params_node != null && (this._params_node.isDirty() || this._params_added_since_last_params_eval); } async evalAll() { var _a; if (this.paramsEvalRequired()) { await this.evalParams(this._paramsList); (_a = this._params_node) == null ? void 0 : _a.removeDirtyState(); this._params_added_since_last_params_eval = false; } } // // // HOOKS // // onParamsCreated(hook_name, hook) { if (this._params_created) { hook(); } else { if (this._post_create_params_hook_names && this._post_create_params_hook_names.includes(hook_name)) { Poly.error(`hook name ${hook_name} already exists`); return; } this._post_create_params_hook_names = this._post_create_params_hook_names || []; this._post_create_params_hook_names.push(hook_name); this._post_create_params_hooks = this._post_create_params_hooks || []; this._post_create_params_hooks.push(hook); } } addOnSceneLoadHook(param_name, method) { this._on_scene_load_hook_names = this._on_scene_load_hook_names || []; this._on_scene_load_hooks = this._on_scene_load_hooks || []; if (!this._on_scene_load_hook_names.includes(param_name)) { this._on_scene_load_hook_names.push(param_name); this._on_scene_load_hooks.push(method); } else { Poly.warn(`hook with name ${param_name} already exists`, this.node); } } _runPostCreateParamsHooks() { if (this._post_create_params_hooks) { for (const hook of this._post_create_params_hooks) { hook(); } } } runOnSceneLoadHooks() { if (this._on_scene_load_hooks) { for (const hook of this._on_scene_load_hooks) { hook(); } } } }