@polygonjs/polygonjs
Version:
node-based WebGL 3D engine https://polygonjs.com
184 lines (183 loc) • 5.86 kB
JavaScript
"use strict";
import { TypedPostNode, PostParamOptions } from "./_Base";
import { EffectPass } from "postprocessing";
import { BuilderEffect } from "./utils/BuilderEffect";
import { NodeParamsConfig, ParamConfig } from "../utils/params/ParamsConfig";
import { GlobalsGeometryHandler } from "../gl/code/globals/Geometry";
import { GlNodeFinder } from "../gl/code/utils/NodeFinder";
import { Poly } from "../../Poly";
import { AssemblerName } from "./../../poly/registers/assemblers/_BaseRegister";
import { PostPersistedConfig } from "./../gl/code/assemblers/post/PostPersistedConfig";
import { PostType } from "./../../poly/registers/nodes/types/Post";
import defaultFragmentShader from "./gl/builder.glsl";
import { NodeContext } from "../../poly/NodeContext";
class BuilderPostParamsConfig extends NodeParamsConfig {
constructor() {
super(...arguments);
/** @param effect amount */
this.useInput1OuputBuffer = ParamConfig.BOOLEAN(1, {
...PostParamOptions
});
}
}
const ParamsConfig = new BuilderPostParamsConfig();
export class BuilderPostNode extends TypedPostNode {
constructor() {
super(...arguments);
this.paramsConfig = ParamsConfig;
this.persisted_config = new PostPersistedConfig(this);
this._assemblerController = this._createAssemblerController();
this._childrenControllerContext = NodeContext.GL;
// private _cook_main_without_inputs_when_dirty_bound = this._cook_main_without_inputs_when_dirty.bind(this);
// private async _cook_main_without_inputs_when_dirty() {
// await this.cookController.cookMainWithoutInputs();
// }
// override cook() {
// this.compileIfRequired();
// this.cookController.endCook();
// }
/**
*
* FRAGMENT SHADER UPDATE
*
*/
this._fragmentShader = defaultFragmentShader;
this._uniforms = {};
}
static type() {
return PostType.BUILDER;
}
usedAssembler() {
return AssemblerName.GL_POST;
}
_createAssemblerController() {
const assemblerController = Poly.assemblersRegister.assembler(this, this.usedAssembler());
if (assemblerController) {
const globalsHandler = new GlobalsGeometryHandler();
assemblerController.setAssemblerGlobalsHandler(globalsHandler);
return assemblerController;
}
}
assemblerController() {
return this._assemblerController;
}
initializeNode() {
super.initializeNode();
this.io.inputs.setCount(0, 2);
this.addPostDirtyHook("_cook_main_without_inputs_when_dirty", () => {
this.compileIfRequired();
});
}
createNode(node_class, options) {
return super.createNode(node_class, options);
}
children() {
return super.children();
}
nodesByType(type) {
return super.nodesByType(type);
}
childrenAllowed() {
if (this.assemblerController()) {
return super.childrenAllowed();
}
return false;
}
sceneReadonly() {
return this.assemblerController() == null;
}
fragmentShader() {
return this._fragmentShader;
}
setFragmentShader(fragmentShader) {
this._fragmentShader = fragmentShader;
this._updatePasses();
}
uniforms() {
return this._uniforms;
}
setUniforms(uniforms) {
this._uniforms = uniforms;
this._updatePasses();
}
shaders_by_name() {
return {
fragment: this._fragmentShader
};
}
compileIfRequired() {
var _a;
if ((_a = this.assemblerController()) == null ? void 0 : _a.compileRequired()) {
try {
this.compile();
} catch (err) {
const message = err.message || "failed to compile";
this.states.error.set(message);
}
}
}
compile() {
const assemblerController = this.assemblerController();
if (!assemblerController) {
return;
}
const outputNodes = GlNodeFinder.findOutputNodes(this);
if (outputNodes.length == 0) {
this.states.error.set("one output node is required");
return;
}
if (outputNodes.length > 1) {
this.states.error.set("only one output node allowed");
return;
}
const outputNode = outputNodes[0];
if (outputNode) {
const rootNodes = outputNodes;
assemblerController.assembler.set_root_nodes(rootNodes);
assemblerController.assembler.updateFragmentShader();
const fragmentShader = assemblerController.assembler.fragment_shader();
const uniforms = assemblerController.assembler.uniforms();
if (fragmentShader && uniforms) {
this._fragmentShader = fragmentShader;
this._uniforms = uniforms;
}
BuilderPostNode.handleDependencies(this, assemblerController.assembler.uniformsTimeDependent());
}
if (this._fragmentShader && this._uniforms) {
this._updatePasses();
}
assemblerController.post_compile();
}
static handleDependencies(node, timeDependent, uniforms) {
}
/**
*
* PASS CREATE / UPDATE
*
*/
createPass(context) {
this.compileIfRequired();
const composerInput1 = this._createEffectComposer(context);
composerInput1.autoRenderToScreen = false;
const clonedContextInput1 = { ...context };
clonedContextInput1.composer = composerInput1;
this._addPassFromInput(1, clonedContextInput1);
const effect = new BuilderEffect(composerInput1, {
fragmentShader: this._fragmentShader,
useOutputBuffer: this.pv.useInput1OuputBuffer
});
const pass = new EffectPass(context.camera, effect);
this.updatePass(pass);
return pass;
}
updatePass(pass) {
const effect = pass.effects[0];
effect.updateUniforms(this._uniforms);
effect.updateFragmentShader(this._fragmentShader);
pass.fullscreenMaterial.needsUpdate = true;
}
_createEffectComposer(context) {
const parentNode = this._postProcessNetworkNode();
return parentNode.effectsComposerController.createEffectsComposer(context);
}
}