#

API Docs for: 1.4.0
Show: Inherited Protected Private Deprecated

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

    /**
     * @author Mat Groves
     *
     * Big thanks to the very clever Matt DesLauriers <mattdesl> https://github.com/mattdesl/
     * for creating the original pixi version!
     *
     * Heavily inspired by LibGDX's WebGLSpriteBatch:
     * https://github.com/libgdx/libgdx/blob/master/gdx/src/com/badlogic/gdx/graphics/g2d/WebGLSpriteBatch.java
     */

    PIXI.WebGLSpriteBatch = function(gl)
    {

        this.size = 2000;
        this.vertSize = 6;

        //the total number of floats in our batch
        var numVerts = this.size * 4 *  this.vertSize;
        //the total number of indices in our batch
        var numIndices = this.size * 6;

         //vertex data
        this.vertices = new Float32Array(numVerts);
        //index data
        this.indices = new Uint16Array(numIndices);

        this.lastIndexCount = 0;

        for (var i=0, j=0; i < numIndices; i += 6, j += 4)
        {
            this.indices[i + 0] = j + 0;
            this.indices[i + 1] = j + 1;
            this.indices[i + 2] = j + 2;
            this.indices[i + 3] = j + 0;
            this.indices[i + 4] = j + 2;
            this.indices[i + 5] = j + 3;
        }

        this.drawing = false;
        this.currentBatchSize = 0;
        this.currentBaseTexture = null;

        this.setContext(gl);
    };

    PIXI.WebGLSpriteBatch.prototype.setContext = function(gl)
    {
        this.gl = gl;

        // create a couple of buffers
        this.vertexBuffer = gl.createBuffer();
        this.indexBuffer = gl.createBuffer();

        // 65535 is max index, so 65535 / 6 = 10922.

        //upload the index data
        gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer);
        gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, this.indices, gl.STATIC_DRAW);

        gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer);
        gl.bufferData(gl.ARRAY_BUFFER, this.vertices, gl.DYNAMIC_DRAW);

        this.currentBlendMode = 99999;
    };

    PIXI.WebGLSpriteBatch.prototype.begin = function(renderSession)
    {
        this.renderSession = renderSession;
        this.shader = this.renderSession.shaderManager.defaultShader;

        this.start();
    };

    PIXI.WebGLSpriteBatch.prototype.end = function()
    {
        this.flush();
    };

    PIXI.WebGLSpriteBatch.prototype.render = function(sprite)
    {
        // check texture..
        if(sprite.texture.baseTexture !== this.currentBaseTexture || this.currentBatchSize >= this.size)
        {
            this.flush();
            this.currentBaseTexture = sprite.texture.baseTexture;
        }

        // check blend mode
        if(sprite.blendMode !== this.currentBlendMode)
        {
            this.setBlendMode(sprite.blendMode);
        }

        // get the uvs for the texture
        var uvs = sprite._uvs || sprite.texture._uvs;
        // if the uvs have not updated then no point rendering just yet!
        if(!uvs)return;

        // get the sprites current alpha
        var alpha = sprite.worldAlpha;
        var tint = sprite.tint;

        var  verticies = this.vertices;

        var width = sprite.texture.frame.width;
        var height = sprite.texture.frame.height;

        // TODO trim??
        var aX = sprite.anchor.x;
        var aY = sprite.anchor.y;

        var w0, w1, h0, h1;

        if (sprite.texture.trimmed)
        {
            // if the sprite is trimmed then we need to add the extra space before transforming the sprite coords..
            var trim = sprite.texture.trim;

            w1 = trim.x - aX * trim.realWidth;
            w0 = w1 + width;

            h1 = trim.y - aY * trim.realHeight;
            h0 = h1 + height;
        }
        else
        {
            w0 = (width ) * (1-aX);
            w1 = (width ) * -aX;

            h0 = height * (1-aY);
            h1 = height * -aY;
        }

        var index = this.currentBatchSize * 4 * this.vertSize;

        var worldTransform = sprite.worldTransform;

        var a = worldTransform[0];
        var b = worldTransform[3];
        var c = worldTransform[1];
        var d = worldTransform[4];
        var tx = worldTransform[2];
        var ty = worldTransform[5];

        // xy
        verticies[index++] = a * w1 + c * h1 + tx;
        verticies[index++] = d * h1 + b * w1 + ty;
        // uv
        verticies[index++] = uvs[0];
        verticies[index++] = uvs[1];
        // color
        verticies[index++] = alpha;
        verticies[index++] = tint;

        // xy
        verticies[index++] = a * w0 + c * h1 + tx;
        verticies[index++] = d * h1 + b * w0 + ty;
        // uv
        verticies[index++] = uvs[2];
        verticies[index++] = uvs[3];
        // color
        verticies[index++] = alpha;
        verticies[index++] = tint;

        // xy
        verticies[index++] = a * w0 + c * h0 + tx;
        verticies[index++] = d * h0 + b * w0 + ty;
        // uv
        verticies[index++] = uvs[4];
        verticies[index++] = uvs[5];
        // color
        verticies[index++] = alpha;
        verticies[index++] = tint;

        // xy
        verticies[index++] = a * w1 + c * h0 + tx;
        verticies[index++] = d * h0 + b * w1 + ty;
        // uv
        verticies[index++] = uvs[6];
        verticies[index++] = uvs[7];
        // color
        verticies[index++] = alpha;
        verticies[index++] = tint;

        // increment the batchs
        this.currentBatchSize++;

    };

    PIXI.WebGLSpriteBatch.prototype.renderTilingSprite = function(tilingSprite)
    {
        var texture = tilingSprite.texture;

        if(texture.baseTexture !== this.currentBaseTexture || this.currentBatchSize >= this.size)
        {
            this.flush();
            this.currentBaseTexture = texture.baseTexture;
        }

         // check blend mode
        if(tilingSprite.blendMode !== this.currentBlendMode)
        {
            this.setBlendMode(tilingSprite.blendMode);
        }

         // set the textures uvs temporarily
        // TODO create a seperate texture so that we can tile part of a texture

        if(!tilingSprite._uvs)tilingSprite._uvs = new Float32Array(8);

        var uvs = tilingSprite._uvs;

        var offsetX =  tilingSprite.tilePosition.x/texture.baseTexture.width;
        var offsetY =  tilingSprite.tilePosition.y/texture.baseTexture.height;

        var scaleX =  (tilingSprite.width / texture.baseTexture.width)  / tilingSprite.tileScale.x;
        var scaleY =  (tilingSprite.height / texture.baseTexture.height) / tilingSprite.tileScale.y;

        uvs[0] = 0 - offsetX;
        uvs[1] = 0 - offsetY;

        uvs[2] = (1 * scaleX) - offsetX;
        uvs[3] = 0 - offsetY;

        uvs[4] = (1 * scaleX) - offsetX;
        uvs[5] = (1 * scaleY) - offsetY;

        uvs[6] = 0 - offsetX;
        uvs[7] = (1 *scaleY) - offsetY;

        // get the tilingSprites current alpha
        var alpha = tilingSprite.worldAlpha;
        var tint = tilingSprite.tint;

        var  verticies = this.vertices;

        var width = tilingSprite.width;
        var height = tilingSprite.height;

        // TODO trim??
        var aX = tilingSprite.anchor.x; // - tilingSprite.texture.trim.x
        var aY = tilingSprite.anchor.y; //- tilingSprite.texture.trim.y
        var w0 = width * (1-aX);
        var w1 = width * -aX;

        var h0 = height * (1-aY);
        var h1 = height * -aY;

        var index = this.currentBatchSize * 4 * this.vertSize;

        var worldTransform = tilingSprite.worldTransform;

        var a = worldTransform[0];
        var b = worldTransform[3];
        var c = worldTransform[1];
        var d = worldTransform[4];
        var tx = worldTransform[2];
        var ty = worldTransform[5];

        // xy
        verticies[index++] = a * w1 + c * h1 + tx;
        verticies[index++] = d * h1 + b * w1 + ty;
        // uv
        verticies[index++] = uvs[0];
        verticies[index++] = uvs[1];
        // color
        verticies[index++] = alpha;
        verticies[index++] = tint;

        // xy
        verticies[index++] = a * w0 + c * h1 + tx;
        verticies[index++] = d * h1 + b * w0 + ty;
        // uv
        verticies[index++] = uvs[2];
        verticies[index++] = uvs[3];
        // color
        verticies[index++] = alpha;
        verticies[index++] = tint;

        // xy
        verticies[index++] = a * w0 + c * h0 + tx;
        verticies[index++] = d * h0 + b * w0 + ty;
        // uv
        verticies[index++] = uvs[4];
        verticies[index++] = uvs[5];
        // color
        verticies[index++] = alpha;
        verticies[index++] = tint;

        // xy
        verticies[index++] = a * w1 + c * h0 + tx;
        verticies[index++] = d * h0 + b * w1 + ty;
        // uv
        verticies[index++] = uvs[6];
        verticies[index++] = uvs[7];
        // color
        verticies[index++] = alpha;
        verticies[index++] = tint;

        // increment the batchs
        this.currentBatchSize++;
    };

    PIXI.WebGLSpriteBatch.prototype.flush = function()
    {
        // If the batch is length 0 then return as there is nothing to draw
        if (this.currentBatchSize===0)return;

        var gl = this.gl;

        // bind the current texture
        gl.bindTexture(gl.TEXTURE_2D, this.currentBaseTexture._glTextures[gl.id] || PIXI.createWebGLTexture(this.currentBaseTexture, gl));

        // upload the verts to the buffer
        var view = this.vertices.subarray(0, this.currentBatchSize * 4 * this.vertSize);
        gl.bufferSubData(gl.ARRAY_BUFFER, 0, view);

        // now draw those suckas!
        gl.drawElements(gl.TRIANGLES, this.currentBatchSize * 6, gl.UNSIGNED_SHORT, 0);

        // then reset the batch!
        this.currentBatchSize = 0;

        // increment the draw count
        this.renderSession.drawCount++;
    };

    PIXI.WebGLSpriteBatch.prototype.stop = function()
    {
        this.flush();
    };

    PIXI.WebGLSpriteBatch.prototype.start = function()
    {
        var gl = this.gl;

        // bind the main texture
        gl.activeTexture(gl.TEXTURE0);

        // bind the buffers
        gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer);
        gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer);

        // set the projection
        var projection = this.renderSession.projection;
        gl.uniform2f(this.shader.projectionVector, projection.x, projection.y);

        // set the pointers
        var stride =  this.vertSize * 4;
        gl.vertexAttribPointer(this.shader.aVertexPosition, 2, gl.FLOAT, false, stride, 0);
        gl.vertexAttribPointer(this.shader.aTextureCoord, 2, gl.FLOAT, false, stride, 2 * 4);
        gl.vertexAttribPointer(this.shader.colorAttribute, 2, gl.FLOAT, false, stride, 4 * 4);

        // set the blend mode..
        if(this.currentBlendMode !== PIXI.blendModes.NORMAL)
        {
            this.setBlendMode(PIXI.blendModes.NORMAL);
        }
    };

    PIXI.WebGLSpriteBatch.prototype.setBlendMode = function(blendMode)
    {
        this.flush();

        this.currentBlendMode = blendMode;

        var blendModeWebGL = PIXI.blendModesWebGL[this.currentBlendMode];
        this.gl.blendFunc(blendModeWebGL[0], blendModeWebGL[1]);
    };