cables_dev/cables/src/libs/cgl/shadergraph/cgl_shadergraphprogram.js
import { Events } from "cables-shared-client";
import { ShaderGraph } from "./cgl_shadergraph.js";
const ShaderGraphProgram = class extends Events
{
constructor(op, port, type)
{
super();
this._type = type;
this._op = op;
this._port = port;
this.uniforms = [];
this._opIdsHeadFuncSrc = {};
this._opIdsFuncCallSrc = {};
this._functionIdInHead = {};
this._headFuncSrc = "";
this._headUniSrc = "";
this._callFuncStack = [];
this.finalSrc = "";
}
setOpShaderId(op)
{
if (!op.shaderId) op.shaderId = CGL.ShaderGraph.getNewId();
}
replaceId(op, txt)
{
this.setOpShaderId(op);
return txt.replaceAll("_ID", "_" + op.shaderId);
}
addOpShaderFuncCode(op)
{
if (!op.sgOp)
{
console.warn("HAS NO SGOP!", op);
return;
}
// if (!op.sgOp.info) return;
if (this._opIdsHeadFuncSrc[op.id])
{
// console.log("already exist",op.name,op.id);
return;
}
this._opIdsHeadFuncSrc[op.id] = true;
if (op.sgOp && op.sgOp._defines)
for (let i = 0; i < op.sgOp._defines.length; i++)
this._headFuncSrc += "#define " + op.sgOp._defines[i][0] + "\n";
// if (op.shaderSrc)
// {
// let src = op.shaderSrc.endl();// +"/* "+op.id+" */".endl();;
// src = this.replaceId(op, src);
// this._headFuncSrc += src;
// }
if (op.sgOp.info)
{
// console.log(op.sgOp.info.name, op.sgOp.info.functions);
for (let i = 0; i < op.sgOp.info.functions.length; i++)
{
const f = op.sgOp.info.functions[i];
// console.log("ADD FUNCTION CODE", f.name, f.uniqueName, this._functionIdInHead[f.uniqueName]);
if (this._functionIdInHead[f.uniqueName]) continue;
if (!f.name.contains("_ID")) this._functionIdInHead[f.uniqueName] = true;
let src = f.src;
// console.log("src", src);
src = this.replaceId(op, src);
this._headFuncSrc += src;
}
}
if (op.shaderUniforms)
{
for (let i = 0; i < op.shaderUniforms.length; i++)
{
const uni = op.shaderUniforms[i];
if (!uni.static)
{
this._headUniSrc += "uniform " + CGL.Uniform.glslTypeString(uni.type) + " " + uni.name + ";".endl();
this.uniforms.push(uni);
}
else
this._headUniSrc += this.uniformAsStaticVar(uni);
}
}
}
uniformAsStaticVar(uni)
{
const typeStr = CGL.Uniform.glslTypeString(uni.type);
let str = "";
if (typeStr == "float")
{
let floatStr = String(uni.ports[0].get());
if (!floatStr.contains("."))floatStr += ".";
str = typeStr + " " + uni.name + " = " + floatStr + ";".endl();
}
else
{
str = typeStr + " " + uni.name + "=" + typeStr + "(";
for (let i = 0; i < uni.ports.length; i++)
{
str += uni.ports[i].get();
if (i != uni.ports.length - 1)str += ",";
}
str += ");".endl();
}
return str;
}
callFunc(op, convertTo)
{
this.setOpShaderId(op);
let callstr = " ";
const varname = "var_" + op.getTitle() + "_" + op.shaderId;
if (convertTo)callstr += ShaderGraph.typeConv(convertTo) + " " + varname + " = ";
if (this._opIdsFuncCallSrc[op.shaderId])
{
if (varname) return varname;
return;
}
this._opIdsFuncCallSrc[op.shaderId] = true;
callstr += this.replaceId(op, op.shaderFunc || "") + "(";
this.addOpShaderFuncCode(op);
const numObjectPorts = this.countObjectInputPorts(op);
let count = 0;
for (let i = 0; i < op.portsIn.length; i++)
{
let paramStr = "";
const p = op.portsIn[i];
if (p.uiAttribs.objType == "sg_void") continue;
if (p.type != CABLES.OP_PORT_TYPE_OBJECT) continue;
// parameters...
if (p.isLinked())
{
for (let j = 0; j < p.links.length; j++)
{
const otherPort = p.links[j].getOtherPort(p);
paramStr = this._getPortParamStr(otherPort, p.uiAttribs.objType);
// console.log("objtype", p.uiAttribs.objType);
this.addOpShaderFuncCode(otherPort.op);
}
}
else
{
this.addOpShaderFuncCode(p.op);
// if (p.uiAttribs.objType == "sg_sampler2D")
// {
// // callstr = "vec4(1.0)";
// // break;
// // paramStr = "null";
// // break;
// }
// else
// {
paramStr = ShaderGraph.getDefaultParameter(p.uiAttribs.objType);
// }
}
if (p.op.shaderCodeOperator)
{
callstr += paramStr;
if (count < numObjectPorts - 1) callstr += " " + p.op.shaderCodeOperator + " ";
}
else
if (paramStr)
{
callstr += paramStr;
if (count < numObjectPorts - 1) callstr += ", ";
}
count++;
}
callstr += ");";
this._callFuncStack.push(callstr);
return varname;
}
countObjectInputPorts(op)
{
let count = 0;
for (let i = 0; i < op.portsIn.length; i++)
if (op.portsIn[i].type == CABLES.OP_PORT_TYPE_OBJECT)
count++;
return count;
}
_getPortParamStr(p, convertTo)
{
let paramStr = "";
if (p.op.shaderVar)
{
paramStr = p.op.shaderVar;
}
else
if (p.direction == CABLES.PORT_DIR_OUT)
{
paramStr += this.callFunc(p.op, p.uiAttribs.objType);
}
if (convertTo && convertTo != p.uiAttribs.objType)
{
paramStr = ShaderGraph.convertTypes(convertTo, p.uiAttribs.objType, paramStr);
}
return paramStr;
}
compile()
{
const port = this._port;
const l = port.links;
this.uniforms = [];
this._callFuncStack = [];
this._functionIdInHead = {};
this._opIdsFuncCallSrc = {};
this._opIdsHeadFuncSrc = {};
this._headFuncSrc = "";
this._headUniSrc = "";
let callSrc = "";
for (let i = 0; i < l.length; i++)
{
const lnk = l[i];
callSrc += this.callFunc(lnk.getOtherPort(port).op) + ";".endl();
}
callSrc = this._callFuncStack.join("\n");
let src = "".endl() + "{{MODULES_HEAD}}".endl().endl();
// console.log("COMPILE", this._type);
// todo use shader attrib system...
if (this._type == "frag") src += "IN vec2 texCoord;".endl().endl();
if (this._type == "vert") src += "IN vec3 vPosition;".endl() +
"IN vec2 attrTexCoord;".endl() +
"OUT vec2 texCoord;".endl().endl();
if (this._type == "vert")src += "".endl() +
"UNI mat4 projMatrix;".endl().endl() +
"UNI mat4 viewMatrix;".endl().endl() +
"UNI mat4 modelMatrix;".endl().endl();
src +=
this._headUniSrc.endl().endl() +
this._headFuncSrc.endl().endl() +
"void main()".endl() +
"{".endl();
if (this._type == "frag")src += " {{MODULE_BEGIN_FRAG}}".endl();
if (this._type == "vert")src += " {{MODULE_BEGIN_VERTEX}}".endl();
src += callSrc.endl() +
"}".endl();
this.finalSrc = src;
this.emitEvent("compiled");
}
};
export { ShaderGraphProgram };