@polygonjs/polygonjs
Version:
node-based WebGL 3D engine https://polygonjs.com
138 lines (130 loc) • 4.5 kB
text/typescript
/**
* triggers an event when a parameter has changed
*
*
*/
import {TypedEventNode} from './_Base';
import {EventConnectionPoint, EventConnectionPointType} from '../utils/io/connections/Event';
import {NodeParamsConfig, ParamConfig} from '../utils/params/ParamsConfig';
import {CoreGraphNode} from '../../../core/graph/CoreGraphNode';
import {BaseParamType} from '../../params/_Base';
import {RampParam} from '../../params/Ramp';
function previousValueParamOptions() {
return {
cook: false,
hidden: true,
};
}
class ParamEventParamsConfig extends NodeParamsConfig {
/** @param set to listen or stop listening to the param */
active = ParamConfig.BOOLEAN(true);
/** @param the parameter to update */
param = ParamConfig.PARAM_PATH('', {
dependentOnFoundParam: false,
paramSelection: true,
computeOnDirty: true,
});
boolean = ParamConfig.BOOLEAN(0, previousValueParamOptions());
integer = ParamConfig.INTEGER(0, previousValueParamOptions());
float = ParamConfig.FLOAT(0, previousValueParamOptions());
vector2 = ParamConfig.VECTOR2([0, 0], previousValueParamOptions());
vector3 = ParamConfig.VECTOR3([0, 0, 0], previousValueParamOptions());
vector4 = ParamConfig.VECTOR4([0, 0, 0, 0], previousValueParamOptions());
ramp = ParamConfig.RAMP(RampParam.DEFAULT_VALUE, previousValueParamOptions());
string = ParamConfig.STRING('', previousValueParamOptions());
}
const ParamsConfig = new ParamEventParamsConfig();
export class ParamEventNode extends TypedEventNode<ParamEventParamsConfig> {
override paramsConfig = ParamsConfig;
static override type(): Readonly<'param'> {
return 'param';
}
static readonly OUTPUT_NAME = 'valueChanged';
override initializeNode() {
this.io.outputs.setNamedOutputConnectionPoints([
new EventConnectionPoint(ParamEventNode.OUTPUT_NAME, EventConnectionPointType.BASE),
]);
}
override async cook() {
await this._listenToParam();
this.cookController.endCook();
}
override dispose() {
super.dispose();
this._reset();
}
private _reset() {
this.__paramCoreGraphNode__?.graphRemove();
}
private _resolvedParam: BaseParamType | null = null;
private _previousValueParam: BaseParamType | null = null;
private async _listenToParam() {
if (!this.p.param) {
// in the current implementation,
// cook is triggered a first time when the node is created (before the params are created),
// and therefore _listenToParam.
// So we need to check that the parameter does exist
return;
}
if (this._resolvedParam) {
this.__paramCoreGraphNode__?.removeGraphInput(this._resolvedParam);
this._previousValueParam = null;
}
if (this.p.param.isDirty()) {
// TODO: investigate occasions
// where the referenced param is recomputed
// (such as in a material builder)
// and this node refers to an old param
await this.p.param.compute();
}
this._resolvedParam = this.p.param.value.param();
if (this._resolvedParam) {
const previousValueParams = [
this.p.boolean,
this.p.integer,
this.p.float,
this.p.vector2,
this.p.vector3,
this.p.vector4,
this.p.ramp,
this.p.string,
];
for (const p of previousValueParams) {
if (p.type() == this._resolvedParam.type()) {
this._previousValueParam = p;
await this._resolvedParam.compute();
this._previousValueParam.copyValue(this._resolvedParam);
}
}
if (!this._previousValueParam) {
this.states.error.set(
`param type ${this._resolvedParam.type()} is not supported, availables are: ${previousValueParams
.map((p) => p.type())
.join(', ')}`
);
}
this.paramGraphNode().addGraphInput(this._resolvedParam);
}
}
private paramGraphNode() {
return (this.__paramCoreGraphNode__ = this.__paramCoreGraphNode__ || this._createCoreGraphNode());
}
private __paramCoreGraphNode__: CoreGraphNode | undefined;
private _createCoreGraphNode() {
const node = new CoreGraphNode(this.scene(), 'event/Param');
node.dirtyController.addPostDirtyHook('onParamDirty', this._onParamDirtyBound);
return node;
}
private _onParamDirtyBound = this._onParamDirty.bind(this);
private async _onParamDirty() {
if (!(this._resolvedParam && this._previousValueParam)) {
return;
}
await this._resolvedParam.compute();
const valueChanged = !this._resolvedParam.isValueEqual(this._previousValueParam.value);
if (valueChanged) {
this._previousValueParam.copyValue(this._resolvedParam);
this.dispatchEventToOutput(ParamEventNode.OUTPUT_NAME, {});
}
}
}