#

API Docs for: 1.4.3
Show: Inherited Protected Private Deprecated

# File: src/pixi/renderers/webgl/utils/WebGLFilterManager.js

    /**
     * @author Mat Groves http://matgroves.com/ @Doormat23
     */

    PIXI.WebGLFilterManager = function(gl, transparent)
    {
        this.transparent = transparent;

        this.filterStack = [];

        this.offsetX = 0;
        this.offsetY = 0;

        this.setContext(gl);
    };

    // API

    PIXI.WebGLFilterManager.prototype.setContext = function(gl)
    {
        this.gl = gl;
        this.texturePool = [];

        this.initShaderBuffers();
    };

    PIXI.WebGLFilterManager.prototype.begin = function(renderSession, buffer)
    {
        this.renderSession = renderSession;
        this.defaultShader = renderSession.shaderManager.defaultShader;

        var projection = this.renderSession.projection;

        this.width = projection.x * 2;
        this.height = -projection.y * 2;
        this.buffer = buffer;
    };

    PIXI.WebGLFilterManager.prototype.pushFilter = function(filterBlock)
    {
        var gl = this.gl;

        var projection = this.renderSession.projection;
        var offset = this.renderSession.offset;

        // filter program
        // OPTIMISATION - the first filter is free if its a simple color change?
        this.filterStack.push(filterBlock);

        var filter = filterBlock.filterPasses[0];

        this.offsetX += filterBlock.target.filterArea.x;
        this.offsetY += filterBlock.target.filterArea.y;

        var texture = this.texturePool.pop();
        if(!texture)
        {
            texture = new PIXI.FilterTexture(this.gl, this.width, this.height);
        }
        else
        {
            texture.resize(this.width, this.height);
        }

        gl.bindTexture(gl.TEXTURE_2D,  texture.texture);

    //    this.getBounds(filterBlock.target);

        filterBlock.target.filterArea = filterBlock.target.getBounds();
       // console.log(filterBlock.target.filterArea)
       // console.log(filterBlock.target.filterArea);
        // addpadding?
        //displayObject.filterArea.x

        var filterArea = filterBlock.target.filterArea;

        var padidng = filter.padding;
        filterArea.x -= padidng;
        filterArea.y -= padidng;
        filterArea.width += padidng * 2;
        filterArea.height += padidng * 2;

        // cap filter to screen size..
        if(filterArea.x < 0)filterArea.x = 0;
        if(filterArea.width > this.width)filterArea.width = this.width;
        if(filterArea.y < 0)filterArea.y = 0;
        if(filterArea.height > this.height)filterArea.height = this.height;

        //gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA,  filterArea.width, filterArea.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
        gl.bindFramebuffer(gl.FRAMEBUFFER, texture.frameBuffer);

        //console.log(filterArea)
        // set view port
        gl.viewport(0, 0, filterArea.width, filterArea.height);

        projection.x = filterArea.width/2;
        projection.y = -filterArea.height/2;

        offset.x = -filterArea.x;
        offset.y = -filterArea.y;

        //console.log(PIXI.defaultShader.projectionVector)
        // update projection
        gl.uniform2f(this.defaultShader.projectionVector, filterArea.width/2, -filterArea.height/2);
        gl.uniform2f(this.defaultShader.offsetVector, -filterArea.x, -filterArea.y);
        //PIXI.primitiveProgram

        gl.colorMask(true, true, true, true);
        gl.clearColor(0,0,0, 0);
        gl.clear(gl.COLOR_BUFFER_BIT);

        //filter.texture = texture;
        filterBlock._glFilterTexture = texture;

        //console.log("PUSH")
    };

    PIXI.WebGLFilterManager.prototype.popFilter = function()
    {
        var gl = this.gl;
        var filterBlock = this.filterStack.pop();
        var filterArea = filterBlock.target.filterArea;
        var texture = filterBlock._glFilterTexture;
        var projection = this.renderSession.projection;
        var offset = this.renderSession.offset;

        if(filterBlock.filterPasses.length > 1)
        {
            gl.viewport(0, 0, filterArea.width, filterArea.height);

            gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer);

            this.vertexArray[0] = 0;
            this.vertexArray[1] = filterArea.height;

            this.vertexArray[2] = filterArea.width;
            this.vertexArray[3] = filterArea.height;

            this.vertexArray[4] = 0;
            this.vertexArray[5] = 0;

            this.vertexArray[6] = filterArea.width;
            this.vertexArray[7] = 0;

            gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.vertexArray);

            gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer);
            // now set the uvs..
            this.uvArray[2] = filterArea.width/this.width;
            this.uvArray[5] = filterArea.height/this.height;
            this.uvArray[6] = filterArea.width/this.width;
            this.uvArray[7] = filterArea.height/this.height;

            gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.uvArray);

            var inputTexture = texture;
            var outputTexture = this.texturePool.pop();
            if(!outputTexture)outputTexture = new PIXI.FilterTexture(this.gl, this.width, this.height);

            // need to clear this FBO as it may have some left over elements from a previous filter.
            gl.bindFramebuffer(gl.FRAMEBUFFER, outputTexture.frameBuffer );
            gl.clear(gl.COLOR_BUFFER_BIT);

            gl.disable(gl.BLEND);

            for (var i = 0; i < filterBlock.filterPasses.length-1; i++)
            {
                var filterPass = filterBlock.filterPasses[i];

                gl.bindFramebuffer(gl.FRAMEBUFFER, outputTexture.frameBuffer );

                // set texture
                gl.activeTexture(gl.TEXTURE0);
                gl.bindTexture(gl.TEXTURE_2D, inputTexture.texture);

                // draw texture..
                //filterPass.applyFilterPass(filterArea.width, filterArea.height);
                this.applyFilterPass(filterPass, filterArea, filterArea.width, filterArea.height);

                // swap the textures..
                var temp = inputTexture;
                inputTexture = outputTexture;
                outputTexture = temp;
            }

            gl.enable(gl.BLEND);

            texture = inputTexture;
            this.texturePool.push(outputTexture);
        }

        var filter = filterBlock.filterPasses[filterBlock.filterPasses.length-1];

        this.offsetX -= filterArea.x;
        this.offsetY -= filterArea.y;

        var sizeX = this.width;
        var sizeY = this.height;

        var offsetX = 0;
        var offsetY = 0;

        var buffer = this.buffer;

        // time to render the filters texture to the previous scene
        if(this.filterStack.length === 0)
        {
            gl.colorMask(true, true, true, this.transparent);
        }
        else
        {
            var currentFilter = this.filterStack[this.filterStack.length-1];
            filterArea = currentFilter.target.filterArea;

            sizeX = filterArea.width;
            sizeY = filterArea.height;

            offsetX = filterArea.x;
            offsetY = filterArea.y;

            buffer =  currentFilter._glFilterTexture.frameBuffer;
        }

        // TODO need toremove thease global elements..
        projection.x = sizeX/2;
        projection.y = -sizeY/2;

        offset.x = offsetX;
        offset.y = offsetY;

        filterArea = filterBlock.target.filterArea;

        var x = filterArea.x-offsetX;
        var y = filterArea.y-offsetY;

        // update the buffers..
        // make sure to flip the y!
        gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer);

        this.vertexArray[0] = x;
        this.vertexArray[1] = y + filterArea.height;

        this.vertexArray[2] = x + filterArea.width;
        this.vertexArray[3] = y + filterArea.height;

        this.vertexArray[4] = x;
        this.vertexArray[5] = y;

        this.vertexArray[6] = x + filterArea.width;
        this.vertexArray[7] = y;

        gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.vertexArray);

        gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer);

        this.uvArray[2] = filterArea.width/this.width;
        this.uvArray[5] = filterArea.height/this.height;
        this.uvArray[6] = filterArea.width/this.width;
        this.uvArray[7] = filterArea.height/this.height;

        gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.uvArray);

        gl.viewport(0, 0, sizeX, sizeY);
        // bind the buffer
        gl.bindFramebuffer(gl.FRAMEBUFFER, buffer );

        // set the blend mode!
        //gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA)

        // set texture
        gl.activeTexture(gl.TEXTURE0);
        gl.bindTexture(gl.TEXTURE_2D, texture.texture);

        // apply!
        //filter.applyFilterPass(sizeX, sizeY);
        this.applyFilterPass(filter, filterArea, sizeX, sizeY);

        // now restore the regular shader..
        gl.useProgram(this.defaultShader.program);
        gl.uniform2f(this.defaultShader.projectionVector, sizeX/2, -sizeY/2);
        gl.uniform2f(this.defaultShader.offsetVector, -offsetX, -offsetY);

        // return the texture to the pool
        this.texturePool.push(texture);
        filterBlock._glFilterTexture = null;
    };

    PIXI.WebGLFilterManager.prototype.applyFilterPass = function(filter, filterArea, width, height)
    {
        // use program
        var gl = this.gl;
        var shader = filter.shaders[gl.id];

        if(!shader)
        {
            shader = new PIXI.PixiShader(gl);

            shader.fragmentSrc = filter.fragmentSrc;
            shader.uniforms = filter.uniforms;
            shader.init();

            filter.shaders[gl.id] = shader;
        }

        // set the shader
        gl.useProgram(shader.program);

        gl.uniform2f(shader.projectionVector, width/2, -height/2);
        gl.uniform2f(shader.offsetVector, 0,0);

        if(filter.uniforms.dimensions)
        {
            //console.log(filter.uniforms.dimensions)
            filter.uniforms.dimensions.value[0] = this.width;//width;
            filter.uniforms.dimensions.value[1] = this.height;//height;
            filter.uniforms.dimensions.value[2] = this.vertexArray[0];
            filter.uniforms.dimensions.value[3] = this.vertexArray[5];//filterArea.height;
        //  console.log(this.vertexArray[5])
        }

        shader.syncUniforms();

        gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer);
        gl.vertexAttribPointer(shader.aVertexPosition, 2, gl.FLOAT, false, 0, 0);

        gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer);
        gl.vertexAttribPointer(shader.aTextureCoord, 2, gl.FLOAT, false, 0, 0);

        gl.bindBuffer(gl.ARRAY_BUFFER, this.colorBuffer);
        gl.vertexAttribPointer(shader.colorAttribute, 2, gl.FLOAT, false, 0, 0);

        gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer);

        // draw the filter...
        gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0 );

        this.renderSession.drawCount++;
    };

    PIXI.WebGLFilterManager.prototype.initShaderBuffers = function()
    {
        var gl = this.gl;

        // create some buffers
        this.vertexBuffer = gl.createBuffer();
        this.uvBuffer = gl.createBuffer();
        this.colorBuffer = gl.createBuffer();
        this.indexBuffer = gl.createBuffer();

        // bind and upload the vertexs..
        // keep a reference to the vertexFloatData..
        this.vertexArray = new Float32Array([0.0, 0.0,
                                             1.0, 0.0,
                                             0.0, 1.0,
                                             1.0, 1.0]);

        gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer);
        gl.bufferData(
        gl.ARRAY_BUFFER,
        this.vertexArray,
        gl.STATIC_DRAW);

        // bind and upload the uv buffer
        this.uvArray = new Float32Array([0.0, 0.0,
                                         1.0, 0.0,
                                         0.0, 1.0,
                                         1.0, 1.0]);

        gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer);
        gl.bufferData(
        gl.ARRAY_BUFFER,
        this.uvArray,
        gl.STATIC_DRAW);

        this.colorArray = new Float32Array([1.0, 0xFFFFFF,
                                            1.0, 0xFFFFFF,
                                            1.0, 0xFFFFFF,
                                            1.0, 0xFFFFFF]);

        gl.bindBuffer(gl.ARRAY_BUFFER, this.colorBuffer);
        gl.bufferData(
        gl.ARRAY_BUFFER,
        this.colorArray,
        gl.STATIC_DRAW);

        // bind and upload the index
        gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer);
        gl.bufferData(
        gl.ELEMENT_ARRAY_BUFFER,
        new Uint16Array([0, 1, 2, 1, 3, 2]),
        gl.STATIC_DRAW);
    };

    PIXI.WebGLFilterManager.prototype.destroy = function()
    {
        var gl = this.gl;

        this.filterStack = null;

        this.offsetX = 0;
        this.offsetY = 0;

        // destroy textures
        for (var i = 0; i < this.texturePool.length; i++) {
            this.texturePool.destroy();
        }

        this.texturePool = null;

        //destroy buffers..
        gl.deleteBuffer(this.vertexBuffer);
        gl.deleteBuffer(this.uvBuffer);
        gl.deleteBuffer(this.colorBuffer);
        gl.deleteBuffer(this.indexBuffer);
    };

    PIXI.FilterTexture = function(gl, width, height)
    {
        this.gl = gl;

        // next time to create a frame buffer and texture
        this.frameBuffer = gl.createFramebuffer();
        this.texture = gl.createTexture();

        gl.bindTexture(gl.TEXTURE_2D,  this.texture);
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
        gl.bindFramebuffer(gl.FRAMEBUFFER, this.framebuffer );

        gl.bindFramebuffer(gl.FRAMEBUFFER, this.frameBuffer );
        gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, this.texture, 0);

        this.resize(width, height);
    };

    PIXI.FilterTexture.prototype.clear = function()
    {
        var gl = this.gl;

        gl.clearColor(0,0,0, 0);
        gl.clear(gl.COLOR_BUFFER_BIT);
    };

    PIXI.FilterTexture.prototype.resize = function(width, height)
    {
        if(this.width === width && this.height === height) return;

        this.width = width;
        this.height = height;

        var gl = this.gl;

        gl.bindTexture(gl.TEXTURE_2D,  this.texture);
        gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA,  width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);

    };

    PIXI.FilterTexture.prototype.destroy = function()
    {
        var gl = this.gl;
        gl.deleteFramebuffer( this.frameBuffer );
        gl.deleteTexture( this.texture );

        this.frameBuffer = null;
        this.texture = null;
    };