cables_dev/cables/src/core/cgl/cgl_textureeffect.js
- import { Logger } from "cables-shared-client";
- import { Texture } from "./cgl_texture.js";
- import { MESHES } from "./cgl_simplerect.js";
-
- const TextureEffect = function (cgl, options)
- {
- this._cgl = cgl;
- this._log = new Logger("cgl_TextureEffect");
-
- if (!cgl.TextureEffectMesh) this.createMesh();
-
- this._textureSource = null;
- this._options = options;
- this.name = options.name || "unknown";
-
- // TODO: do we still need the options ?
- // var opts=options ||
- // {
- // isFloatingPointTexture:false,
- // filter:CGL.Texture.FILTER_LINEAR
- // };
- // if(options && options.fp)opts.isFloatingPointTexture=true;
-
- this.imgCompVer = 0;
- this.aspectRatio = 1;
- this._textureTarget = null; // new CGL.Texture(this._cgl,opts);
- this._frameBuf = this._cgl.gl.createFramebuffer();
- this._frameBuf2 = this._cgl.gl.createFramebuffer();
- this._renderbuffer = this._cgl.gl.createRenderbuffer();
- this._renderbuffer2 = this._cgl.gl.createRenderbuffer();
- this.switched = false;
- this.depth = false;
- };
-
- TextureEffect.prototype.dispose = function ()
- {
- if (this._renderbuffer) this._cgl.gl.deleteRenderbuffer(this._renderbuffer);
- if (this._frameBuf) this._cgl.gl.deleteFramebuffer(this._frameBuf);
- if (this._renderbuffer2) this._cgl.gl.deleteRenderbuffer(this._renderbuffer2);
- if (this._frameBuf2) this._cgl.gl.deleteFramebuffer(this._frameBuf2);
- };
-
- TextureEffect.prototype.getWidth = function ()
- {
- return this._textureSource.width;
- };
-
- TextureEffect.prototype.getHeight = function ()
- {
- return this._textureSource.height;
- };
-
- TextureEffect.prototype.setSourceTexture = function (tex)
- {
- if (tex === null)
- {
- this._textureSource = new Texture(this._cgl);
- this._textureSource.setSize(16, 16);
- }
- else
- {
- this._textureSource = tex;
- }
-
- if (!this._textureSource.compareSettings(this._textureTarget))
- {
- if (this._textureTarget) this._textureTarget.delete();
-
- this._textureTarget = this._textureSource.clone();
-
- this._cgl.profileData.profileEffectBuffercreate++;
-
- this._cgl.gl.bindFramebuffer(this._cgl.gl.FRAMEBUFFER, this._frameBuf);
-
- this._cgl.gl.bindRenderbuffer(this._cgl.gl.RENDERBUFFER, this._renderbuffer);
-
- // if(tex.textureType==CGL.Texture.TYPE_FLOAT) this._cgl.gl.renderbufferStorage(this._cgl.gl.RENDERBUFFER,this._cgl.gl.RGBA32F, this._textureSource.width,this._textureSource.height);
- // else this._cgl.gl.renderbufferStorage(this._cgl.gl.RENDERBUFFER,this._cgl.gl.RGBA8, this._textureSource.width,this._textureSource.height);
-
- if (this.depth) this._cgl.gl.renderbufferStorage(this._cgl.gl.RENDERBUFFER, this._cgl.gl.DEPTH_COMPONENT16, this._textureSource.width, this._textureSource.height);
- this._cgl.gl.framebufferTexture2D(this._cgl.gl.FRAMEBUFFER, this._cgl.gl.COLOR_ATTACHMENT0, this._cgl.gl.TEXTURE_2D, this._textureTarget.tex, 0);
- if (this.depth) this._cgl.gl.framebufferRenderbuffer(this._cgl.gl.FRAMEBUFFER, this._cgl.gl.DEPTH_ATTACHMENT, this._cgl.gl.RENDERBUFFER, this._renderbuffer);
-
- // this._cgl.gl.framebufferTexture2D(this._cgl.gl.FRAMEBUFFER, this._cgl.gl.COLOR_ATTACHMENT0, this._cgl.gl.TEXTURE_2D, this._textureTarget.tex, 0);
-
- this._cgl.gl.bindTexture(this._cgl.gl.TEXTURE_2D, null);
- this._cgl.gl.bindRenderbuffer(this._cgl.gl.RENDERBUFFER, null);
- this._cgl.gl.bindFramebuffer(this._cgl.gl.FRAMEBUFFER, null);
-
- this._cgl.gl.bindFramebuffer(this._cgl.gl.FRAMEBUFFER, this._frameBuf2);
-
- this._cgl.gl.bindRenderbuffer(this._cgl.gl.RENDERBUFFER, this._renderbuffer2);
-
- // if(tex.textureType==CGL.Texture.TYPE_FLOAT) this._cgl.gl.renderbufferStorage(this._cgl.gl.RENDERBUFFER,this._cgl.gl.RGBA32F, this._textureSource.width,this._textureSource.height);
- // else this._cgl.gl.renderbufferStorage(this._cgl.gl.RENDERBUFFER,this._cgl.gl.RGBA8, this._textureSource.width,this._textureSource.height);
-
- if (this.depth) this._cgl.gl.renderbufferStorage(this._cgl.gl.RENDERBUFFER, this._cgl.gl.DEPTH_COMPONENT16, this._textureSource.width, this._textureSource.height);
- this._cgl.gl.framebufferTexture2D(this._cgl.gl.FRAMEBUFFER, this._cgl.gl.COLOR_ATTACHMENT0, this._cgl.gl.TEXTURE_2D, this._textureSource.tex, 0);
-
- if (this.depth) this._cgl.gl.framebufferRenderbuffer(this._cgl.gl.FRAMEBUFFER, this._cgl.gl.DEPTH_ATTACHMENT, this._cgl.gl.RENDERBUFFER, this._renderbuffer2);
-
- // this._cgl.gl.framebufferTexture2D(this._cgl.gl.FRAMEBUFFER, this._cgl.gl.COLOR_ATTACHMENT0, this._cgl.gl.TEXTURE_2D, this._textureSource.tex, 0);
-
- this._cgl.gl.bindTexture(this._cgl.gl.TEXTURE_2D, null);
- this._cgl.gl.bindRenderbuffer(this._cgl.gl.RENDERBUFFER, null);
- this._cgl.gl.bindFramebuffer(this._cgl.gl.FRAMEBUFFER, null);
- }
-
- this.aspectRatio = this._textureSource.width / this._textureSource.height;
- };
- TextureEffect.prototype.continueEffect = function ()
- {
- this._cgl.pushDepthTest(false);
- this._cgl.pushModelMatrix();
- this._cgl.pushPMatrix();
- // todo why two pushs?
-
-
-
- this._cgl.pushViewPort(0, 0, this.getCurrentTargetTexture().width, this.getCurrentTargetTexture().height);
-
-
-
- mat4.perspective(this._cgl.pMatrix, 45, this.getCurrentTargetTexture().width / this.getCurrentTargetTexture().height, 0.1, 1100.0); // todo: why?
-
- this._cgl.pushPMatrix();
- mat4.identity(this._cgl.pMatrix);
-
- this._cgl.pushViewMatrix();
- mat4.identity(this._cgl.vMatrix);
-
- this._cgl.pushModelMatrix();
- mat4.identity(this._cgl.mMatrix);
- };
-
-
- TextureEffect.prototype.startEffect = function (bgTex)
- {
- if (!this._textureTarget)
- {
- this._log.warn("effect has no target");
- return;
- }
-
- this.switched = false;
-
- this.continueEffect();
-
- if (bgTex)
- {
- this._bgTex = bgTex;
- }
- this._countEffects = 0;
- };
-
- TextureEffect.prototype.endEffect = function ()
- {
- this._cgl.popDepthTest();
- this._cgl.popModelMatrix();
-
- this._cgl.popPMatrix();
- this._cgl.popModelMatrix();
- this._cgl.popViewMatrix();
-
- this._cgl.popPMatrix();
- this._cgl.popViewPort();
- };
-
- TextureEffect.prototype.bind = function ()
- {
- if (this._textureSource === null)
- {
- this._log.warn("no base texture set!");
- return;
- }
-
- if (!this.switched)
- {
- this._cgl.gl.bindFramebuffer(this._cgl.gl.FRAMEBUFFER, this._frameBuf);
- this._cgl.pushGlFrameBuffer(this._frameBuf);
- }
- else
- {
- this._cgl.gl.bindFramebuffer(this._cgl.gl.FRAMEBUFFER, this._frameBuf2);
- this._cgl.pushGlFrameBuffer(this._frameBuf2);
- }
- };
-
- TextureEffect.prototype.finish = function ()
- {
- if (this._textureSource === null)
- {
- this._log.warn("no base texture set!");
- return;
- }
-
- this._cgl.TextureEffectMesh.render(this._cgl.getShader());
-
- this._cgl.gl.bindFramebuffer(this._cgl.gl.FRAMEBUFFER, this._cgl.popGlFrameBuffer());
-
- this._cgl.profileData.profileTextureEffect++;
-
- if (this._textureTarget.filter == Texture.FILTER_MIPMAP)
- {
- if (!this.switched)
- {
- this._cgl.gl.bindTexture(this._cgl.gl.TEXTURE_2D, this._textureTarget.tex);
- this._textureTarget.updateMipMap();
- }
- else
- {
- this._cgl.gl.bindTexture(this._cgl.gl.TEXTURE_2D, this._textureSource.tex);
- this._textureSource.updateMipMap();
- }
-
- this._cgl.gl.bindTexture(this._cgl.gl.TEXTURE_2D, null);
- }
-
- this.switched = !this.switched;
- this._countEffects++;
- };
-
- TextureEffect.prototype.getCurrentTargetTexture = function ()
- {
- if (this.switched) return this._textureSource;
- return this._textureTarget;
- };
-
- TextureEffect.prototype.getCurrentSourceTexture = function ()
- {
- if (this._countEffects == 0 && this._bgTex) return this._bgTex;
-
- if (this.switched) return this._textureTarget;
- return this._textureSource;
- };
-
- TextureEffect.prototype.delete = function ()
- {
- if (this._textureTarget) this._textureTarget.delete();
- if (this._textureSource) this._textureSource.delete();
- this._cgl.gl.deleteRenderbuffer(this._renderbuffer);
- this._cgl.gl.deleteFramebuffer(this._frameBuf);
- };
-
- TextureEffect.prototype.createMesh = function ()
- {
- this._cgl.TextureEffectMesh = MESHES.getSimpleRect(this._cgl, "texEffectRect");
- };
-
- // ---------------------------------------------------------------------------------
-
- TextureEffect.checkOpNotInTextureEffect = function (op)
- {
- if (!op.patch.cgl) return true;
- if (op.uiAttribs.error && !op.patch.cgl.currentTextureEffect)
- {
- op.setUiError("textureeffect", null);
- return true;
- }
- if (!op.patch.cgl.currentTextureEffect) return true;
-
- if (op.patch.cgl.currentTextureEffect && !op.uiAttribs.error)
- {
- op.setUiError("textureeffect", "This op can not be a child of a ImageCompose/texture effect! imagecompose should only have textureeffect childs.", 0);
- return false;
- }
-
- if (op.patch.cgl.currentTextureEffect) return false;
- return true;
- };
-
- TextureEffect.checkOpInEffect = function (op, minver)
- {
- minver = minver || 0;
-
- if (op.patch.cgl.currentTextureEffect)
- {
- if (op.uiAttribs.uierrors && op.patch.cgl.currentTextureEffect.imgCompVer >= minver)
- {
- op.setUiError("texeffect", null);
- return true;
- }
-
- if (minver && op.patch.cgl.currentTextureEffect.imgCompVer < minver)
- {
- op.setUiError("texeffect", "This op must be a child of an ImageCompose op with version >=" + minver + " <span class=\"button-small\" onclick=\"gui.patchView.downGradeOp('" + op.id + "','" + op.name + "')\">Downgrade</span> to previous version", 1);
- }
- }
-
- if (op.patch.cgl.currentTextureEffect) return true;
-
- if (!op.patch.cgl.currentTextureEffect && (!op.uiAttribs.uierrors || op.uiAttribs.uierrors.length == 0))
- {
- op.setUiError("texeffect", "This op must be a child of an ImageCompose op! More infos <a href=\"https://cables.gl/docs/image_composition/image_composition.html\" target=\"_blank\">here</a>. ", 1);
- return false;
- }
-
- if (!op.patch.cgl.currentTextureEffect) return false;
- return true;
- };
-
- TextureEffect.getBlendCode = function (ver)
- {
- let src = "".endl()
- + "vec3 _blend(vec3 base,vec3 blend)".endl()
- + "{".endl()
- + " vec3 colNew=blend;".endl()
- + " #ifdef BM_MULTIPLY".endl()
- + " colNew=base*blend;".endl()
- + " #endif".endl()
- + " #ifdef BM_MULTIPLY_INV".endl()
- + " colNew=base* vec3(1.0)-blend;".endl()
- + " #endif".endl()
- + " #ifdef BM_AVERAGE".endl()
- + " colNew=((base + blend) / 2.0);".endl()
- + " #endif".endl()
- + " #ifdef BM_ADD".endl()
- + " colNew=min(base + blend, vec3(1.0));".endl()
- + " #endif".endl()
- + " #ifdef BM_SUBTRACT_ONE".endl()
- + " colNew=max(base + blend - vec3(1.0), vec3(0.0));".endl()
- + " #endif".endl()
-
- + " #ifdef BM_SUBTRACT".endl()
- + " colNew=base - blend;".endl()
- + " #endif".endl()
-
- + " #ifdef BM_DIFFERENCE".endl()
- + " colNew=abs(base - blend);".endl()
- + " #endif".endl()
- + " #ifdef BM_NEGATION".endl()
- + " colNew=(vec3(1.0) - abs(vec3(1.0) - base - blend));".endl()
- + " #endif".endl()
- + " #ifdef BM_EXCLUSION".endl()
- + " colNew=(base + blend - 2.0 * base * blend);".endl()
- + " #endif".endl()
- + " #ifdef BM_LIGHTEN".endl()
- + " colNew=max(blend, base);".endl()
- + " #endif".endl()
- + " #ifdef BM_DARKEN".endl()
- + " colNew=min(blend, base);".endl()
- + " #endif".endl()
- + " #ifdef BM_OVERLAY".endl()
- + " #define BlendOverlayf(base, blend) (base < 0.5 ? (2.0 * base * blend) : (1.0 - 2.0 * (1.0 - base) * (1.0 - blend)))"
- // .endl()+' #define BlendOverlay(base, blend) Blend(base, blend, BlendOverlayf)'
- // .endl()+' colNew=Blend(base, blend, BlendOverlayf);'
- .endl()
- + " colNew=vec3(BlendOverlayf(base.r, blend.r),BlendOverlayf(base.g, blend.g),BlendOverlayf(base.b, blend.b));".endl()
- + " #endif".endl()
- + " #ifdef BM_SCREEN".endl()
- + " #define BlendScreenf(base, blend) (1.0 - ((1.0 - base) * (1.0 - blend)))"
- // .endl()+' #define BlendScreen(base, blend) Blend(base, blend, BlendScreenf)'
- // .endl()+' colNew=Blend(base, blend, BlendScreenf);'
- .endl()
- + " colNew=vec3(BlendScreenf(base.r, blend.r),BlendScreenf(base.g, blend.g),BlendScreenf(base.b, blend.b));".endl()
- + " #endif".endl()
- + " #ifdef BM_SOFTLIGHT".endl()
- + " #define BlendSoftLightf(base, blend) ((blend < 0.5) ? (2.0 * base * blend + base * base * (1.0 - 2.0 * blend)) : (sqrt(base) * (2.0 * blend - 1.0) + 2.0 * base * (1.0 - blend)))"
- // .endl()+' #define BlendSoftLight(base, blend) Blend(base, blend, BlendSoftLightf)'
- // .endl()+' colNew=Blend(base, blend, BlendSoftLightf);'
- .endl()
- + " colNew=vec3(BlendSoftLightf(base.r, blend.r),BlendSoftLightf(base.g, blend.g),BlendSoftLightf(base.b, blend.b));".endl()
- + " #endif".endl()
- + " #ifdef BM_HARDLIGHT".endl()
- + " #define BlendOverlayf(base, blend) (base < 0.5 ? (2.0 * base * blend) : (1.0 - 2.0 * (1.0 - base) * (1.0 - blend)))"
- // .endl()+' #define BlendOverlay(base, blend) Blend(base, blend, BlendOverlayf)'
- // .endl()+' colNew=Blend(blend, base, BlendOverlayf);'
- .endl()
- + " colNew=vec3(BlendOverlayf(base.r, blend.r),BlendOverlayf(base.g, blend.g),BlendOverlayf(base.b, blend.b));".endl()
- + " #endif".endl()
- + " #ifdef BM_COLORDODGE".endl()
- + " #define BlendColorDodgef(base, blend) ((blend == 1.0) ? blend : min(base / (1.0 - blend), 1.0))"
- // .endl()+' colNew=Blend(base, blend, BlendColorDodgef);'
- .endl()
- + " colNew=vec3(BlendColorDodgef(base.r, blend.r),BlendColorDodgef(base.g, blend.g),BlendColorDodgef(base.b, blend.b));".endl()
- + " #endif".endl()
- + " #ifdef BM_COLORBURN".endl()
- + " #define BlendColorBurnf(base, blend) ((blend == 0.0) ? blend : max((1.0 - ((1.0 - base) / blend)), 0.0))"
- // .endl()+' colNew=Blend(base, blend, BlendColorBurnf);'
- .endl()
- + " colNew=vec3(BlendColorBurnf(base.r, blend.r),BlendColorBurnf(base.g, blend.g),BlendColorBurnf(base.b, blend.b));".endl()
- + " #endif".endl()
-
-
-
-
-
-
-
-
-
-
- + " return colNew;".endl()
- + "}".endl();
-
- if (!ver)
- src += "vec4 cgl_blend(vec4 oldColor,vec4 newColor,float amount)".endl()
- + "{".endl()
- + "vec4 col=vec4( _blend(oldColor.rgb,newColor.rgb) ,1.0);".endl()
- + "col=vec4( mix( col.rgb, oldColor.rgb ,1.0-oldColor.a*amount),1.0);".endl()
- + "return col;".endl()
- + "}".endl();
-
- if (ver >= 3)
- src += "vec4 cgl_blendPixel(vec4 base,vec4 col,float amount)".endl() +
- "{".endl() +
-
- "#ifdef BM_MATH_ADD".endl() +
- " return vec4(base.rgb+col.rgb*amount,1.0);".endl() +
- "#endif".endl() +
-
- "#ifdef BM_MATH_SUB".endl() +
- " return vec4(base.rgb-col.rgb*amount,1.0);".endl() +
- "#endif".endl() +
-
- "#ifdef BM_MATH_MUL".endl() +
- " return vec4(base.rgb*col.rgb*amount,1.0);".endl() +
- "#endif".endl() +
-
- "#ifdef BM_MATH_DIV".endl() +
- " return vec4(base.rgb/col.rgb*amount,1.0);".endl() +
- "#endif".endl() +
-
-
- "#ifndef BM_MATH".endl() +
- "vec3 colNew=_blend(base.rgb,col.rgb);".endl() +
-
- "float newA=clamp(base.a+(col.a*amount),0.,1.);".endl() +
-
- "#ifdef BM_ALPHAMASKED".endl() +
- "newA=base.a;".endl() +
- "#endif".endl() +
-
- "return vec4(".endl() +
- "mix(colNew,base.rgb,1.0-(amount*col.a)),".endl() +
- "newA);".endl() +
-
- "#endif".endl() +
- "}".endl();
-
- return src;
- };
-
- TextureEffect.onChangeBlendSelect = function (shader, blendName, maskAlpha = false)
- {
- blendName = String(blendName);
- shader.toggleDefine("BM_NORMAL", blendName == "normal");
- shader.toggleDefine("BM_MULTIPLY", blendName == "multiply");
- shader.toggleDefine("BM_MULTIPLY_INV", blendName == "multiply invert");
- shader.toggleDefine("BM_AVERAGE", blendName == "average");
- shader.toggleDefine("BM_ADD", blendName == "add");
- shader.toggleDefine("BM_SUBTRACT_ONE", blendName == "subtract one");
- shader.toggleDefine("BM_SUBTRACT", blendName == "subtract");
- shader.toggleDefine("BM_DIFFERENCE", blendName == "difference");
- shader.toggleDefine("BM_NEGATION", blendName == "negation");
- shader.toggleDefine("BM_EXCLUSION", blendName == "exclusion");
- shader.toggleDefine("BM_LIGHTEN", blendName == "lighten");
- shader.toggleDefine("BM_DARKEN", blendName == "darken");
- shader.toggleDefine("BM_OVERLAY", blendName == "overlay");
- shader.toggleDefine("BM_SCREEN", blendName == "screen");
- shader.toggleDefine("BM_SOFTLIGHT", blendName == "softlight");
- shader.toggleDefine("BM_HARDLIGHT", blendName == "hardlight");
- shader.toggleDefine("BM_COLORDODGE", blendName == "color dodge");
- shader.toggleDefine("BM_COLORBURN", blendName == "color burn");
-
- shader.toggleDefine("BM_MATH_ADD", blendName == "Math Add");
- shader.toggleDefine("BM_MATH_SUB", blendName == "Math Subtract");
- shader.toggleDefine("BM_MATH_MUL", blendName == "Math Multiply");
- shader.toggleDefine("BM_MATH_DIV", blendName == "Math Divide");
-
- shader.toggleDefine("BM_MATH", blendName.indexOf("Math ") == 0);
-
-
- shader.toggleDefine("BM_ALPHAMASKED", maskAlpha);
- };
-
- TextureEffect.AddBlendSelect = function (op, name, defaultMode)
- {
- const p = op.inValueSelect(name || "Blend Mode", [
- "normal", "lighten", "darken", "multiply", "multiply invert", "average", "add", "subtract", "difference", "negation", "exclusion", "overlay", "screen", "color dodge", "color burn", "softlight", "hardlight", "subtract one",
- "Math Add",
- "Math Subtract",
- "Math Multiply",
- "Math Divide",
-
- ], defaultMode || "normal");
- return p;
- };
-
- TextureEffect.AddBlendAlphaMask = function (op, name, defaultMode)
- {
- const p = op.inSwitch(name || "Alpha Mask", ["Off", "On"], defaultMode || "Off");
- return p;
- };
-
- TextureEffect.setupBlending = function (op, shader, blendPort, amountPort, alphaMaskPort)
- {
- const onChange = () =>
- {
- let maskAlpha = false;
- if (alphaMaskPort) maskAlpha = alphaMaskPort.get() == "On";
- TextureEffect.onChangeBlendSelect(shader, blendPort.get(), maskAlpha);
-
- let str = blendPort.get();
- if (str == "normal") str = null;
- else if (str == "multiply") str = "mul";
- else if (str == "multiply invert") str = "mulinv";
- else if (str == "lighten") str = "light";
- else if (str == "darken") str = "darken";
- else if (str == "average") str = "avg";
- else if (str == "subtract one") str = "sub one";
- else if (str == "subtract") str = "sub";
- else if (str == "difference") str = "diff";
- else if (str == "negation") str = "neg";
- else if (str == "exclusion") str = "exc";
- else if (str == "overlay") str = "ovl";
- else if (str == "color dodge") str = "dodge";
- else if (str == "color burn") str = "burn";
- else if (str == "softlight") str = "soft";
- else if (str == "hardlight") str = "hard";
- else if (str == "Math Add") str = "+";
- else if (str == "Math Subtract") str = "-";
- else if (str == "Math Multiply") str = "*";
- else if (str == "Math Divide") str = "/";
-
- op.setUiAttrib({ "extendTitle": str });
- };
- op.setPortGroup("Blending", [blendPort, amountPort, alphaMaskPort]);
-
- let maskAlpha = false;
-
- blendPort.onChange = onChange;
- if (alphaMaskPort)
- {
- alphaMaskPort.onChange = onChange;
- maskAlpha = alphaMaskPort.get() == "On";
- }
-
- TextureEffect.onChangeBlendSelect(shader, blendPort.get(), maskAlpha);
- };
-
- export { TextureEffect };