Newer
Older
pixi.js / src / core / renderers / webgl / utils / RenderTarget.js
@mathew groves mathew groves on 23 Jan 2015 5 KB big changes
var math = require('../../../math'),
    CONST = require('../../../const');

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

/**
* @class FrameBuffer
* @constructor
* @param gl {WebGLContext} the current WebGL drawing context
* @param width {Number} the horizontal range of the filter
* @param height {Number} the vertical range of the filter
* @param scaleMode {Number} See {{#crossLink "PIXI/scaleModes:property"}}PIXI.scaleModes{{/crossLink}} for possible values
*/
var RenderTarget = function(gl, width, height, scaleMode, root)
{
    /**
     * @property gl
     * @type WebGLContext
     */
    this.gl = gl;

    // next time to create a frame buffer and texture

    /**
     * @property frameBuffer
     * @type Any
     */
    this.frameBuffer = null;

    /**
     * @property texture
     * @type Any
     */
    this.texture = null;

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

    this.resolution = 1;

    this.projectionMatrix = new math.Matrix();

    this.frame = null;

    /**
     * @property scaleMode
     * @type Number
     */
    this.scaleMode = scaleMode || CONST.scaleModes.DEFAULT;

    this.root = root;

    if(!this.root)
    {
       // this.flipY = true;
        this.frameBuffer = gl.createFramebuffer();


        /*
            A frame buffer needs a target to render to..
            create a texture and bind it attach it to the framebuffer..
         */

        this.texture = gl.createTexture();

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

        // set the scale properties of the texture..
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, scaleMode === CONST.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST);
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, scaleMode === CONST.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST);
        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.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, this.texture, 0);



        /*
            The stencil buffer is used for masking in pixi
            lets create one and then add attach it to the framebuffer..
         */
        this.stencilBuffer = gl.createRenderbuffer();
        gl.bindRenderbuffer(gl.RENDERBUFFER, this.stencilBuffer);
        gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.RENDERBUFFER, this.stencilBuffer);
    }

    this.resize(width, height);

};

RenderTarget.prototype.constructor = RenderTarget;
module.exports = RenderTarget;

/**
* Clears the filter texture.
*
* @method clear
*/
RenderTarget.prototype.clear = function()
{
    var gl = this.gl;

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

RenderTarget.prototype.activate = function()
{
    //TOOD refactor usage of frame..
    var gl = this.gl,
        pm = this.projectionMatrix;

    gl.bindFramebuffer(gl.FRAMEBUFFER, this.frameBuffer);
        
    var frame = this.frame;

    if(frame)
    {
        if (!this.root)
        {
            pm.a = 1 / frame.width*2;
            pm.d = 1 / frame.height*2;

            pm.tx = -1 - frame.x * pm.a; 
            pm.ty = -1 - frame.y * pm.d;
        }
        else
        {
            pm.a = 1 / frame.width*2;
            pm.d = -1 / frame.height*2;

            pm.tx = -1 - frame.x * pm.a; 
            pm.ty = 1 - frame.y * pm.d;
        }

        gl.viewport(0,0, frame.width, frame.height);

    }
    
    // gl.viewport(frame.x, frame.y, frame.width, frame.height);
};

/**
 * Resizes the texture to the specified width and height
 *
 * @method resize
 * @param width {Number} the new width of the texture
 * @param height {Number} the new height of the texture
 */
RenderTarget.prototype.resize = function(width, height)
{
    width = width | 0;
    height = height | 0;

    if (this.width === width && this.height === height) {
        return;
    }

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

    this.projectionMatrix = new math.Matrix();

    if (!this.root)
    {
        var gl = this.gl;

        this.projectionMatrix.a = 1/width*2;
        this.projectionMatrix.d = 1/height*2;

        this.projectionMatrix.tx = -1;
        this.projectionMatrix.ty = -1;

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

        gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA,  width , height , 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
        // update the stencil buffer width and height
        gl.bindRenderbuffer(gl.RENDERBUFFER, this.stencilBuffer);
        gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_STENCIL,  width  , height );
    }
    else
    {
        this.projectionMatrix.a = 1/width*2;
        this.projectionMatrix.d = -1/height*2;

        this.projectionMatrix.tx = -1;
        this.projectionMatrix.ty = 1;
    }
};

/**
* Destroys the filter texture.
*
* @method destroy
*/
RenderTarget.prototype.destroy = function()
{
    var gl = this.gl;
    gl.deleteFramebuffer( this.frameBuffer );
    gl.deleteTexture( this.texture );

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