cables_dev/cables/src/core/cgp/cgp_shader.js
import { Logger } from "cables-shared-client";
import Uniform from "./cgp_uniform.js";
import { preproc } from "../cg/preproc.js";
import { CgShader } from "../cg/cg_shader.js";
import Binding from "./cgp_binding.js";
export default class Shader extends CgShader
{
constructor(_cgp, _name, options = {})
{
super();
if (!_cgp) throw new Error("shader constructed without cgp " + _name);
this._log = new Logger("cgp_shader");
this._cgp = _cgp;
this._name = _name;
this._uniforms = [];
this.compute = options.compute || false;
if (!_name) this._log.stack("no shader name given");
this._name = _name || "unknown";
this._compileReason = "";
this.gpuShaderModule = null;
this._needsRecompile = true;
this.bindingCounter = 0;
this.bindCountlastFrame = -1;
this._bindingIndexCount = 0;
this.defaultBindingVert = new Binding(_cgp, "vsUniforms", { "stage": "vert", "bindingType": "uniform", "index": this._bindingIndexCount++ });
this.defaultBindingFrag = new Binding(_cgp, "fsUniforms", { "stage": "frag", "bindingType": "uniform", "index": this._bindingIndexCount++ });
this.defaultBindingComp = new Binding(_cgp, "computeUniforms", { "bindingType": "uniform", "index": this._bindingIndexCount++ });
this.bindingsFrag = [this.defaultBindingFrag];
this.bindingsVert = [this.defaultBindingVert];
this.bindingsComp = [this.defaultBindingComp];
if (!this.compute)
{
this.uniModelMatrix = this.addUniformVert("m4", "modelMatrix");
this.uniViewMatrix = this.addUniformVert("m4", "viewMatrix");
this.uniProjMatrix = this.addUniformVert("m4", "projMatrix");
this.uniNormalMatrix = this.addUniformVert("m4", "normalMatrix");
this.uniModelViewMatrix = this.addUniformVert("m4", "modelViewMatrix");
this._tempNormalMatrix = mat4.create();
this._tempModelViewMatrix = mat4.create();
}
this._src = "";
this._cgp.on("deviceChange", () =>
{
this.gpuShaderModule = null;
this._needsRecompile = "device changed";
});
}
incBindingCounter()
{
if (this.bindCountlastFrame != this._cgp.frame) this.bindingCounter = 0;
else this.bindingCounter++;
this.bindCountlastFrame = this._cgp.frame;
}
reInit()
{
}
get isValid()
{
return this._isValid;
}
get uniforms()
{
return this._uniforms;
}
getName()
{
return this._name;
}
setWhyCompile(why)
{
this._compileReason = why;
}
getNewBindingIndex()
{
return ++this._bindingIndexCount;
}
setSource(src)
{
this._src = src;
this.setWhyCompile("Source changed");
this._needsRecompile = true;
}
_replaceMods(vs)
{
let srcHeadVert = "";
for (let i = 0; i < this._moduleNames.length; i++)
{
let srcVert = "";
for (let j = 0; j < this._modules.length; j++)
{
const mod = this._modules[j];
if (mod.name == this._moduleNames[i])
{
srcHeadVert += "\n//---- MOD: group:" + mod.group + ": idx:" + j + " - prfx:" + mod.prefix + " - " + mod.title + " ------\n";
srcVert += "\n\n//---- MOD: " + mod.title + " / " + mod.priority + " ------\n";
if (mod.attributes)
for (let k = 0; k < mod.attributes.length; k++)
{
const r = this._getAttrSrc(mod.attributes[k], false);
if (r.srcHeadVert)srcHeadVert += r.srcHeadVert;
if (r.srcVert)srcVert += r.srcVert;
}
srcHeadVert += mod.srcHead || "";
srcVert += mod.srcBody || "";
srcHeadVert += "\n//---- end mod ------\n";
srcVert += "\n//---- end mod ------\n";
srcVert = srcVert.replace(/{{mod}}/g, mod.prefix);
srcHeadVert = srcHeadVert.replace(/{{mod}}/g, mod.prefix);
srcVert = srcVert.replace(/MOD_/g, mod.prefix);
srcHeadVert = srcHeadVert.replace(/MOD_/g, mod.prefix);
}
}
vs = vs.replace("{{" + this._moduleNames[i] + "}}", srcVert);
}
vs = vs.replace("{{MODULES_HEAD}}", srcHeadVert);
return vs;
}
getProcessedSource()
{
const defs = {};
for (let i = 0; i < this._defines.length; i++)
defs[this._defines[i][0]] = this._defines[i][1] || true;
let src = preproc(this._src, defs);
let bindingsHeadVert = "";
for (let i = 0; i < this.bindingsFrag.length; i++)
bindingsHeadVert += this.bindingsFrag[i].getShaderHeaderCode();
let bindingsHeadFrag = "";
for (let i = 0; i < this.bindingsVert.length; i++)
bindingsHeadFrag += this.bindingsVert[i].getShaderHeaderCode();
src = bindingsHeadFrag + "\n\n////////////////\n\n" + bindingsHeadVert + "\n\n////////////////\n\n" + src;
src = this._replaceMods(src);
return src;
// console.log("----------------\n", src, "\n----------------------------");
}
compile()
{
console.log("compile", this._compileReason);
this._isValid = true;
this._cgp.pushErrorScope("cgp_shader " + this._name);
// console.log(this.getProcessedSource());
this.gpuShaderModule = this._cgp.device.createShaderModule({ "code": this.getProcessedSource(), "label": this._name });
this._cgp.popErrorScope(this.error.bind(this));
this._needsRecompile = false;
this.emitEvent("compiled");
}
error(e)
{
this._isValid = false;
}
bind()
{
if (!this.compute)
{
this.uniModelMatrix.setValue(this._cgp.mMatrix);
this.uniViewMatrix.setValue(this._cgp.vMatrix);
this.uniProjMatrix.setValue(this._cgp.pMatrix);
// mat4.invert(this._tempNormalMatrix, this._cgp.mMatrix);
// mat4.transpose(this._tempNormalMatrix, this._tempNormalMatrix);
mat4.mul(this._tempModelViewMatrix, this._cgp.vMatrix, this._cgp.mMatrix);
// mat4.set(this._tempNormalMatrix, this._tempModelViewMatrix);
mat4.invert(this._tempNormalMatrix, this._tempModelViewMatrix);
mat4.transpose(this._tempNormalMatrix, this._tempNormalMatrix);
// cpu billboarding?
// this._tempModelViewMatrix[0 * 4 + 0] = 1.0;
// this._tempModelViewMatrix[0 * 4 + 1] = 0.0;
// this._tempModelViewMatrix[0 * 4 + 2] = 0.0;
// // #ifndef BILLBOARDING_CYLINDRIC
// this._tempModelViewMatrix[1 * 4 + 0] = 0.0;
// this._tempModelViewMatrix[1 * 4 + 1] = 1.0;
// this._tempModelViewMatrix[1 * 4 + 2] = 0.0;
// // #endif
// this._tempModelViewMatrix[2 * 4 + 0] = 0.0;
// this._tempModelViewMatrix[2 * 4 + 1] = 0.0;
// this._tempModelViewMatrix[2 * 4 + 2] = 1.0;
this.uniModelViewMatrix.setValue(this._tempModelViewMatrix);
this.uniNormalMatrix.setValue(this._tempNormalMatrix);
}
if (this._needsRecompile) this.compile();
}
/**
* add a uniform to the fragment shader
* @param {String} type ['f','t', etc]
* @param {String} name
* @param {any} valueOrPort value or port
* @param p2
* @param p3
* @param p4
* @memberof Shader
* @instance
* @function addUniformFrag
* @returns {Uniform}
*/
addUniformFrag(type, name, valueOrPort, p2, p3, p4)
{
const uni = new Uniform(this, type, name, valueOrPort, p2, p3, p4);
uni.shaderType = "frag";
this.defaultBindingFrag.addUniform(uni);
this.needsPipelineUpdate = "add frag uniform";
return uni;
}
/**
* add a uniform to the vertex shader
* @param {String} type ['f','t', etc]
* @param {String} name
* @param {any} valueOrPort value or port
* @param p2
* @param p3
* @param p4
* @memberof Shader
* @instance
* @function addUniformVert
* @returns {Uniform}
*/
addUniformVert(type, name, valueOrPort, p2, p3, p4)
{
const uni = new Uniform(this, type, name, valueOrPort, p2, p3, p4);
uni.shaderType = "vert";
this.defaultBindingVert.addUniform(uni);
this.needsPipelineUpdate = "add ver uniform";
return uni;
}
/**
* add a uniform to all shader programs
* @param {String} type ['f','t', etc]
* @param {String} name
* @param {any} valueOrPort value or port
* @param p2
* @param p3
* @param p4
* @memberof Shader
* @instance
* @function addUniform
* @returns {Uniform}
*/
addUniform(type, name, valueOrPort, p2, p3, p4)
{
const uni = new Uniform(this, type, name, valueOrPort, p2, p3, p4);
uni.shaderType = "both";
return uni;
}
_addUniform(uni)
{
this._uniforms.push(uni);
this.setWhyCompile("add uniform " + name);
this._needsRecompile = true;
}
getUniform(name)
{
for (let i = 0; i < this._uniforms.length; i++)
{
if (this._uniforms[i].getName() == name) return this._uniforms[i];
}
}
/**
* copy current shader
* @function copy
* @memberof Shader
* @instance
* @returns newShader
*/
copy()
{
const shader = new Shader(this._cgp, this._name + " copy");
shader.setSource(this._src);
shader._modules = JSON.parse(JSON.stringify(this._modules));
shader._defines = JSON.parse(JSON.stringify(this._defines));
shader._modGroupCount = this._modGroupCount;
shader._moduleNames = this._moduleNames;
// shader.glPrimitive = this.glPrimitive;
// shader.offScreenPass = this.offScreenPass;
// shader._extensions = this._extensions;
// shader.wireframe = this.wireframe;
// shader._attributes = this._attributes;
for (let i = 0; i < this._uniforms.length; i++) this._uniforms[i].copy(shader);
shader.bindingsFrag = [];
for (let i = 0; i < this.bindingsFrag.length; i++) this.bindingsFrag[i].copy(shader);
shader.defaultBindingFrag = this.bindingsFrag[0];
shader.bindingsVert = [];
for (let i = 0; i < this.bindingsVert.length; i++) this.bindingsVert[i].copy(shader);
shader.defaultBindingVert = this.bindingsVert[0];
shader.bindingsComp = [];
for (let i = 0; i < this.bindingsComp.length; i++) this.bindingsComp[i].copy(shader);
shader.defaultBindingComp = this.bindingsComp[0];
console.log("copyyyyyyyyyy", shader.bindingsVert, this.bindingsVert);
this.setWhyCompile("copy");
shader._needsRecompile = true;
return shader;
}
/**
* copy all uniform values from another shader
* @function copyUniforms
* @memberof Shader
* @instance
* @param origShader uniform values will be copied from this shader
*/
copyUniformValues(origShader)
{
for (let i = 0; i < origShader._uniforms.length; i++)
{
if (!this._uniforms[i])
{
this._log.log("unknown uniform?!");
continue;
}
this.getUniform(origShader._uniforms[i].getName()).set(origShader._uniforms[i].getValue());
}
// this.popTextures();
// for (let i = 0; i < origShader._textureStackUni.length; i++)
// {
// this._textureStackUni[i] = origShader._textureStackUni[i];
// this._textureStackTex[i] = origShader._textureStackTex[i];
// this._textureStackType[i] = origShader._textureStackType[i];
// this._textureStackTexCgl[i] = origShader._textureStackTexCgl[i];
// }
}
}