Newer
Older
pixi.js / src / core / renderers / webgl / systems / ShaderSystem.js
@Mat Groves Mat Groves on 23 Mar 2017 4 KB Rename it all to systems!
import WebGLSystem from './WebGLSystem';
import { GLShader } from 'pixi-gl-core';
import { PRECISION } from '../../../const';
import generateUniformsSync from '../../../shader/generateUniformsSync2';

let UID = 0;

/**
 * Helper class to create a webGL Texture
 *
 * @class
 * @memberof PIXI
 */
export default class ShaderSystem extends WebGLSystem
{
    /**
     * @param {PIXI.WebGLRenderer} renderer - A reference to the current renderer
     */
    constructor(renderer)
    {

        super(renderer);

        /**
         * The current WebGL rendering context
         *
         * @member {WebGLRenderingContext}
         */
        this.gl = null;

        this.shader = null;

        this.id = UID++;
    }

    contextChange(gl)
    {
        this.gl = gl;
    }

    /**
     * Changes the current shader to the one given in parameter
     *
     * @param {PIXI.Shader} shader - the new shader
     * @param {boolean} dontSync - false if the shader should automatically sync its uniforms.
     * @returns {PIXI.glCore.GLShader} the glShader that belongs to the shader.
     */
    bind(shader, dontSync)
    {
        const program = shader.program;
        const glShader = program.glShaders[this.renderer.CONTEXT_UID] || this.generateShader(shader);

        // TODO - some current pixi plugins bypass this.. so it not safe to use yet..
        // if (this.shader !== shader)
        // {
        if (this.shader !== shader)
        {
            this.shader = shader;
            glShader.bind();
        }

        if (!dontSync)
        {
            this.syncUniformGroup(shader.uniformGroup);
        }

        return glShader;
    }

    /**
     * Uploads the uniforms values to the currently bound shader.
     *
     * @param {object} uniforms - the uniforms valiues that be applied to the current shader
     */
    setUniforms(uniforms)
    {
        const shader = this.shader.program;
        const glShader = shader.glShaders[this.renderer.CONTEXT_UID];

        shader.syncUniforms(glShader.uniformData, uniforms, this.renderer);
    }

    setUniformsGroups(uniformGroups)
    {

        const glShader = this.getGLShader();

        const group = uniformGroups[0];
        const syncFunc = group.syncUniforms[this.shader.program.id] || this.createSynGroups(group);

        syncFunc(glShader.uniformData, group.uniforms, this.renderer);

    }

    syncUniformGroup(group)
    {
        const glShader = this.getGLShader();

        if(!group.static || group.dirtyId !== glShader.uniformGroups[group.id])
        {
            glShader.uniformGroups[group.id] = group.dirtyId;
            const syncFunc = group.syncUniforms[this.shader.program.id] || this.createSynGroups(group);

            syncFunc(glShader.uniformData, group.uniforms, this.renderer);
        }

    }

    createSynGroups(group)
    {
        group.syncUniforms[this.shader.program.id] = generateUniformsSync(group, this.shader.program.uniformData);

        return group.syncUniforms[this.shader.program.id];
    }
    /**
     * Returns the underlying GLShade rof the currently bound shader.
     * This can be handy for when you to have a little more control over the setting of your uniforms.
     *
     * @return {PIXI.glCore.Shader} the glShader for the currently bound Shader for this context
     */
    getGLShader()
    {
        if(this.shader)
        {
            return this.shader.program.glShaders[this.renderer.CONTEXT_UID];
        }
        else
        {
            return null;
        }
    }

    /**
     * Generates a GLShader verion of the Shader provided.
     *
     * @private
     * @param {PIXI.Shader} shader the shader that the glShader will be based on.
     * @return {PIXI.glCore.GLShader} A shiney new GLShader
     */
    generateShader(shader)
    {
        const program = shader.program;
        const attribMap = {};

        for (const i in program.attributeData)
        {
            attribMap[i] = program.attributeData[i].location;
        }

        const glShader = new GLShader(this.gl, program.vertexSrc, program.fragmentSrc, PRECISION.DEFAULT, attribMap);

        program.glShaders[this.renderer.CONTEXT_UID] = glShader;

        return glShader;
    }

    /**
     * Destroys this System and removes all its textures
     */
    destroy()
    {
        // TODO implement destroy method for ShaderSystem
        this.destroyed = true;
    }
}