polygonjs-engine
Version:
node-based webgl 3D engine https://polygonjs.com
95 lines (85 loc) • 3.06 kB
text/typescript
import {TypedNode} from '../_Base';
import {NodeContext} from '../../poly/NodeContext';
import {ContainerMap, ContainerClassMap} from '../../containers/utils/ContainerMap';
type Callback<NC extends NodeContext> = (container: ContainerMap[NC] | undefined) => void;
export class TypedContainerController<NC extends NodeContext> {
private _callbacks: Callback<NC>[] = [];
private _callbacks_tmp: Callback<NC>[] = [];
protected _container: ContainerMap[NC];
constructor(protected node: TypedNode<NC, any>) {
const container_class = ContainerClassMap[node.nodeContext()];
this._container = new container_class(this.node as any) as ContainerMap[NC];
}
get container() {
return this._container;
}
async requestContainer(): Promise<ContainerMap[NC]> {
if (this.node.flags?.bypass?.active()) {
return (await this.requestInputContainer(0)) || this._container;
}
if (this.node.isDirty()) {
return new Promise((resolve, reject) => {
this._callbacks.push(resolve);
this.node.cookController.cook_main();
});
}
return this._container;
}
// async requestContainerTEST(): Promise<ContainerMap[NC]> {
// if (this.node.flags?.bypass?.active()) {
// const container = await this.requestInputContainer(0);
// return container || this._container;
// }
// if (this.node.isDirty()) {
// await this.node.cookController.cook_main();
// }
// return this._container;
// }
// TODO: should I merge this into the method above?
// private process_container_request() {
// if (this.node.flags?.bypass?.active()) {
// const input_index = 0;
// this.requestInputContainer(input_index).then((container) => {
// this.node.removeDirtyState();
// if (container) {
// this.notify_requesters(container);
// } else {
// this.node.states.error.set('input invalid');
// }
// });
// } else {
// if (this.node.isDirty()) {
// this.node.cookController.cook_main();
// } else {
// this.notify_requesters();
// }
// }
// }
async requestInputContainer(input_index: number) {
const input_node = (<unknown>this.node.io.inputs.input(input_index)) as TypedNode<NC, any>;
if (input_node) {
return await input_node.requestContainer();
} else {
this.node.states.error.set(`input ${input_index} required`);
this.notify_requesters();
return null;
}
}
notify_requesters(container?: ContainerMap[NC]) {
// make a copy of the callbacks first,
// to ensure that new ones are not added to this list
// in side effects from those callbacks
// (the test suite for the File SOP is a good test for this)
this._callbacks_tmp = this._callbacks.slice(); // clone
this._callbacks.splice(0, this._callbacks.length); // empty
if (!container) {
container = this.node.container_controller.container;
}
let callback: Callback<NC> | undefined;
while ((callback = this._callbacks_tmp.pop())) {
callback(container);
}
this.node.scene().cookController.remove_node(this.node);
}
}
export class BaseContainerController extends TypedContainerController<any> {}