import { NodeMaterialBlockConnectionPointTypes } from "./Enums/nodeMaterialBlockConnectionPointTypes.js"; import { NodeMaterialBlockTargets } from "./Enums/nodeMaterialBlockTargets.js"; import { Effect } from "../effect.js"; /** * Class used to store node based material build state */ export class NodeMaterialBuildState { constructor() { /** Gets or sets a boolean indicating if the current state can emit uniform buffers */ this.supportUniformBuffers = false; /** * Gets the list of emitted attributes */ this.attributes = []; /** * Gets the list of emitted uniforms */ this.uniforms = []; /** * Gets the list of emitted constants */ this.constants = []; /** * Gets the list of emitted samplers */ this.samplers = []; /** * Gets the list of emitted functions */ this.functions = {}; /** * Gets the list of emitted extensions */ this.extensions = {}; /** * Gets the list of emitted prePass outputs - if using the prepass */ this.prePassOutput = {}; /** * Gets the list of emitted counters */ this.counters = {}; /** @internal */ this._attributeDeclaration = ""; /** @internal */ this._uniformDeclaration = ""; /** @internal */ this._constantDeclaration = ""; /** @internal */ this._samplerDeclaration = ""; /** @internal */ this._varyingTransfer = ""; /** @internal */ this._injectAtEnd = ""; this._repeatableContentAnchorIndex = 0; /** @internal */ this._builtCompilationString = ""; /** * Gets the emitted compilation strings */ this.compilationString = ""; } /** * Finalize the compilation strings * @param state defines the current compilation state */ finalize(state) { const emitComments = state.sharedData.emitComments; const isFragmentMode = this.target === NodeMaterialBlockTargets.Fragment; this.compilationString = `\n${emitComments ? "//Entry point\n" : ""}void main(void) {\n${this.compilationString}`; if (this._constantDeclaration) { this.compilationString = `\n${emitComments ? "//Constants\n" : ""}${this._constantDeclaration}\n${this.compilationString}`; } let functionCode = ""; for (const functionName in this.functions) { functionCode += this.functions[functionName] + `\n`; } this.compilationString = `\n${functionCode}\n${this.compilationString}`; if (!isFragmentMode && this._varyingTransfer) { this.compilationString = `${this.compilationString}\n${this._varyingTransfer}`; } if (this._injectAtEnd) { this.compilationString = `${this.compilationString}\n${this._injectAtEnd}`; } this.compilationString = `${this.compilationString}\n}`; if (this.sharedData.varyingDeclaration) { this.compilationString = `\n${emitComments ? "//Varyings\n" : ""}${this.sharedData.varyingDeclaration}\n${this.compilationString}`; } if (this._samplerDeclaration) { this.compilationString = `\n${emitComments ? "//Samplers\n" : ""}${this._samplerDeclaration}\n${this.compilationString}`; } if (this._uniformDeclaration) { this.compilationString = `\n${emitComments ? "//Uniforms\n" : ""}${this._uniformDeclaration}\n${this.compilationString}`; } if (this._attributeDeclaration && !isFragmentMode) { this.compilationString = `\n${emitComments ? "//Attributes\n" : ""}${this._attributeDeclaration}\n${this.compilationString}`; } this.compilationString = "precision highp float;\n" + this.compilationString; this.compilationString = "#if defined(WEBGL2) || defined(WEBGPU)\nprecision highp sampler2DArray;\n#endif\n" + this.compilationString; if (isFragmentMode) { this.compilationString = "#if defined(PREPASS)\r\n#extension GL_EXT_draw_buffers : require\r\nlayout(location = 0) out highp vec4 glFragData[SCENE_MRT_COUNT];\r\nhighp vec4 gl_FragColor;\r\n#endif\r\n" + this.compilationString; } for (const extensionName in this.extensions) { const extension = this.extensions[extensionName]; this.compilationString = `\n${extension}\n${this.compilationString}`; } this._builtCompilationString = this.compilationString; } /** @internal */ get _repeatableContentAnchor() { return `###___ANCHOR${this._repeatableContentAnchorIndex++}___###`; } /** * @internal */ _getFreeVariableName(prefix) { prefix = prefix.replace(/[^a-zA-Z_]+/g, ""); if (this.sharedData.variableNames[prefix] === undefined) { this.sharedData.variableNames[prefix] = 0; // Check reserved words if (prefix === "output" || prefix === "texture") { return prefix + this.sharedData.variableNames[prefix]; } return prefix; } else { this.sharedData.variableNames[prefix]++; } return prefix + this.sharedData.variableNames[prefix]; } /** * @internal */ _getFreeDefineName(prefix) { if (this.sharedData.defineNames[prefix] === undefined) { this.sharedData.defineNames[prefix] = 0; } else { this.sharedData.defineNames[prefix]++; } return prefix + this.sharedData.defineNames[prefix]; } /** * @internal */ _excludeVariableName(name) { this.sharedData.variableNames[name] = 0; } /** * @internal */ _emit2DSampler(name) { if (this.samplers.indexOf(name) < 0) { this._samplerDeclaration += `uniform sampler2D ${name};\n`; this.samplers.push(name); } } /** * @internal */ _emit2DArraySampler(name) { if (this.samplers.indexOf(name) < 0) { this._samplerDeclaration += `uniform sampler2DArray ${name};\n`; this.samplers.push(name); } } /** * @internal */ _getGLType(type) { switch (type) { case NodeMaterialBlockConnectionPointTypes.Float: return "float"; case NodeMaterialBlockConnectionPointTypes.Int: return "int"; case NodeMaterialBlockConnectionPointTypes.Vector2: return "vec2"; case NodeMaterialBlockConnectionPointTypes.Color3: case NodeMaterialBlockConnectionPointTypes.Vector3: return "vec3"; case NodeMaterialBlockConnectionPointTypes.Color4: case NodeMaterialBlockConnectionPointTypes.Vector4: return "vec4"; case NodeMaterialBlockConnectionPointTypes.Matrix: return "mat4"; } return ""; } /** * @internal */ _emitExtension(name, extension, define = "") { if (this.extensions[name]) { return; } if (define) { extension = `#if ${define}\n${extension}\n#endif`; } this.extensions[name] = extension; } /** * @internal */ _emitFunction(name, code, comments) { if (this.functions[name]) { return; } if (this.sharedData.emitComments) { code = comments + `\n` + code; } this.functions[name] = code; } /** * @internal */ _emitCodeFromInclude(includeName, comments, options) { if (options && options.repeatKey) { return `#include<${includeName}>${options.substitutionVars ? "(" + options.substitutionVars + ")" : ""}[0..${options.repeatKey}]\n`; } let code = Effect.IncludesShadersStore[includeName] + "\n"; if (this.sharedData.emitComments) { code = comments + `\n` + code; } if (!options) { return code; } if (options.replaceStrings) { for (let index = 0; index < options.replaceStrings.length; index++) { const replaceString = options.replaceStrings[index]; code = code.replace(replaceString.search, replaceString.replace); } } return code; } /** * @internal */ _emitFunctionFromInclude(includeName, comments, options, storeKey = "") { const key = includeName + storeKey; if (this.functions[key]) { return; } if (!options || (!options.removeAttributes && !options.removeUniforms && !options.removeVaryings && !options.removeIfDef && !options.replaceStrings)) { if (options && options.repeatKey) { this.functions[key] = `#include<${includeName}>${options.substitutionVars ? "(" + options.substitutionVars + ")" : ""}[0..${options.repeatKey}]\n`; } else { this.functions[key] = `#include<${includeName}>${options?.substitutionVars ? "(" + options?.substitutionVars + ")" : ""}\n`; } if (this.sharedData.emitComments) { this.functions[key] = comments + `\n` + this.functions[key]; } return; } this.functions[key] = Effect.IncludesShadersStore[includeName]; if (this.sharedData.emitComments) { this.functions[key] = comments + `\n` + this.functions[key]; } if (options.removeIfDef) { this.functions[key] = this.functions[key].replace(/^\s*?#ifdef.+$/gm, ""); this.functions[key] = this.functions[key].replace(/^\s*?#endif.*$/gm, ""); this.functions[key] = this.functions[key].replace(/^\s*?#else.*$/gm, ""); this.functions[key] = this.functions[key].replace(/^\s*?#elif.*$/gm, ""); } if (options.removeAttributes) { this.functions[key] = this.functions[key].replace(/\s*?attribute .+?;/g, "\n"); } if (options.removeUniforms) { this.functions[key] = this.functions[key].replace(/\s*?uniform .*?;/g, "\n"); } if (options.removeVaryings) { this.functions[key] = this.functions[key].replace(/\s*?(varying|in) .+?;/g, "\n"); } if (options.replaceStrings) { for (let index = 0; index < options.replaceStrings.length; index++) { const replaceString = options.replaceStrings[index]; this.functions[key] = this.functions[key].replace(replaceString.search, replaceString.replace); } } } /** * @internal */ _registerTempVariable(name) { if (this.sharedData.temps.indexOf(name) !== -1) { return false; } this.sharedData.temps.push(name); return true; } /** * @internal */ _emitVaryingFromString(name, type, define = "", notDefine = false) { if (this.sharedData.varyings.indexOf(name) !== -1) { return false; } this.sharedData.varyings.push(name); if (define) { if (define.startsWith("defined(")) { this.sharedData.varyingDeclaration += `#if ${define}\n`; } else { this.sharedData.varyingDeclaration += `${notDefine ? "#ifndef" : "#ifdef"} ${define}\n`; } } this.sharedData.varyingDeclaration += `varying ${type} ${name};\n`; if (define) { this.sharedData.varyingDeclaration += `#endif\n`; } return true; } /** * @internal */ _emitUniformFromString(name, type, define = "", notDefine = false) { if (this.uniforms.indexOf(name) !== -1) { return; } this.uniforms.push(name); if (define) { if (define.startsWith("defined(")) { this._uniformDeclaration += `#if ${define}\n`; } else { this._uniformDeclaration += `${notDefine ? "#ifndef" : "#ifdef"} ${define}\n`; } } this._uniformDeclaration += `uniform ${type} ${name};\n`; if (define) { this._uniformDeclaration += `#endif\n`; } } /** * @internal */ _emitFloat(value) { if (value.toString() === value.toFixed(0)) { return `${value}.0`; } return value.toString(); } } //# sourceMappingURL=nodeMaterialBuildState.js.map