@polygonjs/polygonjs
Version:
node-based WebGL 3D engine https://polygonjs.com
129 lines (115 loc) • 4.08 kB
text/typescript
import {TypedNode} from '../_Base';
import {Material} from 'three';
import {NodeContext} from '../../poly/NodeContext';
import {NodeParamsConfig} from '../utils/params/ParamsConfig';
import {InputCloneMode} from '../../poly/InputCloneMode';
import {FlagsControllerB} from '../utils/FlagsController';
import {BaseController, MaterialTexturesRecord, SetParamsTextureNodesRecord} from './utils/_BaseController';
import {arrayCompact} from '../../../core/ArrayUtils';
import {Poly} from '../../Poly';
/**
*
*
* TypedMatNode is the base class for all nodes that process materials. This inherits from [TypedNode](/docs/api/TypedNode).
*
*/
export abstract class TypedMatNode<M extends Material, K extends NodeParamsConfig> extends TypedNode<
NodeContext.MAT,
K
> {
static override context(): NodeContext {
return NodeContext.MAT;
}
override initializeBaseNode() {
super.initializeBaseNode();
this.io.outputs.setHasOneOutput();
this.addPostDirtyHook('_cookWhenDirty', () => {
setTimeout(this._cookWhenDirtyBound, 0);
});
}
protected _cookWhenDirtyBound = this._cookMainWithoutInputsWhenDirty.bind(this);
protected async _cookMainWithoutInputsWhenDirty() {
await this.cookController.cookMainWithoutInputs();
}
abstract material(): Promise<M | undefined>;
setMaterial(material: M) {
Poly.onSceneUpdatedHooks.runHooks();
this._setContainer(material);
}
}
export abstract class PrimitiveMatNode<M extends Material, K extends NodeParamsConfig> extends TypedMatNode<M, K> {
protected _material: M | undefined;
abstract createMaterial(): M;
__materialSync__() {
return (this._material = this._material || this.createMaterial());
}
async material() {
const container = await this.compute();
// return this.materialSync();
return container.material() as M;
}
override initializeBaseNode() {
super.initializeBaseNode();
this.nameController.add_post_set_fullPath_hook(this.set_material_name.bind(this));
}
private set_material_name() {
if (this._material) {
this._material.name = this.path();
}
}
override setMaterial(material: M) {
this._material = material;
super.setMaterial(material);
}
getTextures(material: M, record: MaterialTexturesRecord) {
for (const controller of this.controllersList) {
controller.getTextures(material, record);
}
}
setParamsFromMaterial(material: M, record: SetParamsTextureNodesRecord) {
for (const controller of this.controllersList) {
controller.setParamsFromMaterial(material, record);
}
}
protected controllersList: Array<BaseController> = [];
protected controllersPromises(material: M): Array<void | Promise<void>> {
const promises = this.controllersList.map((controller) => controller.updateMaterial(material));
const compactPromises: Promise<void>[] = [];
arrayCompact(promises, compactPromises);
return compactPromises;
}
override initializeNode() {
this.params.onParamsCreated('init controllers', () => {
for (const controller of this.controllersList) {
controller.initializeNode();
}
});
}
}
export class UpdateMatNode<M extends Material, K extends NodeParamsConfig> extends TypedMatNode<M, K> {
public override readonly flags: FlagsControllerB = new FlagsControllerB(this);
protected override _cookWhenDirtyBound = this._cookMainWithoutInputsWhenDirty.bind(this);
protected override async _cookMainWithoutInputsWhenDirty() {
await this.cookController.cookMain();
}
async material() {
const container = await this.compute();
return container.material() as M | undefined;
}
override initializeBaseNode() {
super.initializeBaseNode();
this.io.inputs.setCount(1);
this.io.inputs.initInputsClonedState(InputCloneMode.ALWAYS);
}
}
export type BaseMatNodeType = TypedMatNode<Material, any>;
export type BasePrimitiveMatNodeType = PrimitiveMatNode<Material, any>;
export class BaseMatNodeClass extends TypedMatNode<Material, any> {
// createMaterial() {
// return new Material();
// }
async material() {
const container = await this.compute();
return container.material() as Material | undefined;
}
}