Skip to content
  • Martin Flöser's avatar
    [scripting] Support shaders in scripted effects · 7bececfa
    Martin Flöser authored
    The scripting API is extended to support custom fragment shaders. To
    support this a new method addFragmentShader is added taking ShaderTraits
    and fragment shader. The GLShader is not exposed, instead a uint id is
    provided which maps to the GLShader.
    
    This shader id can be used in the animate and set calls to specify the
    shader. The animation object is extended by the "fragmentShader" property.
    
    The shader sources are located in the "shaders" directory of the package
    contents.
    
    E.g. the scale effect extended by the shader of the invert effect will
    have the following layout:
    
       package/contents/
       -> code/
         -> main.js
       -> shaders/
         -> invert_core.frag
         -> invert.frag
    
    The adjustment in code are:
     * in constructor to load the shader
        this.shader = effect.addFragmentShader(Effect.MapTexture, "invert.frag");
     * in animations objects of the slots the additions
       fragmentShader: this.shader
     * using the type Effect.Shader
    
    or in full:
    
            window.scaleInAnimation = animate({
                window: window,
                curve: QEasingCurve.OutCubic,
                duration: this.duration,
                animations: [
                    {
                        type: Effect.Scale,
                        from: this.inScale
                    },
                    {
                        type: Effect.Opacity,
                        from: 0
                    },
                    {
                        type: Effect.Shader,
                        fragmentShader: this.shader
                    }
                ]
            });
    
    The animation settings object supports a "uniform" value which takes the
    string name of the uniform. For this uniform the location is resolved
    and stored in the meta data of the AnimationEffect. This requires the
    type Effect.ShaderUniform.
    
    An example animation:
    
            window.scaleInAnimation = animate({
                window: window,
                curve: QEasingCurve.Linear,
                duration: this.duration,
                animations: [
                    {
                        type: Effect.ShaderUniform,
                        fragmentShader: this.shader,
                        uniform: "uForOpening",
                        from: 1.0,
                        to: 1.0
                    }
                ]
            });
    
    Furthermore a new setUniform scriptable method is added to the
    ScriptedEffect. This allows to update uniforms when the configuration
    changes.
    
    The call takes a generic QJSValue which supports:
     * float
     * array of 2, 3 or 4 components
     * string as color
     * variant as color
    
    An example usage to read a color from the configuration and set it as a
    uniform:
    
        effect.setUniform(this.shaderId,
                          "uEffectColor",
                          effect.readConfig("Color", "white"))
    7bececfa