/**
* @author Mat Groves
*
* Big thanks to the very clever Matt DesLauriers <mattdesl> https://github.com/mattdesl/
* for creating the original pixi version!
* Also a thanks to https://github.com/bchevalier for tweaking the tint and alpha so that they now share 4 bytes on the vertex buffer
*
* Heavily inspired by LibGDX's ParticleBuffer:
* https://github.com/libgdx/libgdx/blob/master/gdx/src/com/badlogic/gdx/graphics/g2d/ParticleBuffer.java
*/
/**
*
* @class
* @private
* @namespace PIXI
* @param renderer {WebGLRenderer} The renderer this sprite batch works for.
*/
function ParticleBuffer(gl, size, shader )
{
this.gl = gl;
/**
*
*
* @member {number}
*/
this.vertSize = 2;
/**
*
*
* @member {number}
*/
this.vertByteSize = this.vertSize * 4;
/**
* The number of images in the SpriteBatch before it flushes.
*
* @member {number}
*/
this.size = size;
this.verticiesData = {
attribute:shader.attributes.aVertexPosition,
dynamic:true,
size:2,
uploadFunction:this.uploadVerticies.bind(this),
offset:0
};
this.positionData = {
attribute:shader.attributes.aPositionCoord,
dynamic:true,
size:2,
uploadFunction:this.uploadPosition.bind(this),
offset:0
};
this.rotationData = {
attribute:shader.attributes.aRotation,
dynamic:true,
size:1,
uploadFunction:this.uploadRotation.bind(this),
offset:0
};
this.uvsData = {
attribute:shader.attributes.aTextureCoord,
dynamic:true,
size:2,
uploadFunction:this.uploadUvs.bind(this),
offset:0
};
this.alphaData = {
attribute:shader.attributes.aColor,
dynamic:true,
size:1,
uploadFunction:this.uploadAlpha.bind(this),
offset:0
};
this.dynamicProperties = [
// this.verticiesData,
this.positionData
// this.rotationData,
// this.uvsData
// this.alphaData
];
this.staticProperties = [
this.verticiesData,
// this.positionData,
this.rotationData,
this.uvsData,
this.alphaData
];
this.staticStride = 0;
this.staticBuffer = null;
this.staticData = null;
this.dynamicStride = 0;
this.dynamicBuffer = null;
this.dynamicData = null;
this.initBuffers();
}
ParticleBuffer.prototype.constructor = ParticleBuffer;
module.exports = ParticleBuffer;
/**
* Sets up the renderer context and necessary buffers.
*
* @private
* @param gl {WebGLContext} the current WebGL drawing context
*/
ParticleBuffer.prototype.initBuffers = function ()
{
var gl = this.gl;
var i;
var property;
var dynamicOffset = 0;
this.dynamicStride = 0;
for (i = 0; i < this.dynamicProperties.length; i++)
{
property = this.dynamicProperties[i];
if(property.dynamic)
{
property.offset = dynamicOffset;
dynamicOffset += property.size;
this.dynamicStride += property.size;
}
}
this.dynamicData = new Float32Array( this.size * this.dynamicStride * 4);
this.dynamicBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, this.dynamicBuffer);
gl.bufferData(gl.ARRAY_BUFFER, this.dynamicData, gl.DYNAMIC_DRAW);
// static //
var staticOffset = 0;
this.staticStride = 0;
for (i = 0; i < this.staticProperties.length; i++)
{
property = this.staticProperties[i];
if(property.dynamic)
{
property.offset = staticOffset;
staticOffset += property.size;
this.staticStride += property.size;
}
}
this.staticData = new Float32Array( this.size * this.staticStride * 4);
this.staticBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, this.staticBuffer);
gl.bufferData(gl.ARRAY_BUFFER, this.staticData, gl.DYNAMIC_DRAW);
};
ParticleBuffer.prototype.upload = function(children, startIndex, amount, uploadStatic)
{
var i, property;
var gl = this.gl;
for (i = 0; i < this.dynamicProperties.length; i++)
{
property = this.dynamicProperties[i];
property.uploadFunction(children, startIndex, amount, this.dynamicData, this.dynamicStride, property.offset);
}
gl.bindBuffer(gl.ARRAY_BUFFER, this.dynamicBuffer);
gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.dynamicData);
if(uploadStatic)
{
for (i = 0; i < this.staticProperties.length; i++)
{
property = this.staticProperties[i];
property.uploadFunction(children, startIndex, amount, this.staticData, this.staticStride, property.offset);
}
gl.bindBuffer(gl.ARRAY_BUFFER, this.staticBuffer);
gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.staticData);
}
};
ParticleBuffer.prototype.uploadVerticies = function (children, startIndex, amount, array, stride, offset)
{
//console.log(">>>", array)
//var vertices = this.vertices,
var sprite,
texture,
trim,
sx,
sy,
w0, w1, h0, h1;
for (var i = 0; i < amount; i++) {
sprite = children[startIndex + i];
texture = sprite._texture;
sx = sprite.scale.x;
sy = sprite.scale.y;
if (texture.trim)
{
// if the sprite is trimmed then we need to add the extra space before transforming the sprite coords..
trim = texture.trim;
w1 = trim.x - sprite.anchor.x * trim.width;
w0 = w1 + texture.crop.width;
h1 = trim.y - sprite.anchor.y * trim.height;
h0 = h1 + texture.crop.height;
}
else
{
w0 = (texture._frame.width ) * (1-sprite.anchor.x);
w1 = (texture._frame.width ) * -sprite.anchor.x;
h0 = texture._frame.height * (1-sprite.anchor.y);
h1 = texture._frame.height * -sprite.anchor.y;
}
// var pos = stride * i;
array[offset] = w1 * sx;
array[offset + 1] = h1 * sy;
array[offset + stride] = w0 * sx;
array[offset + stride + 1] = h1 * sy;
array[offset + stride * 2] = w0 * sx;
array[offset + stride * 2 + 1] = h0 * sy;
array[offset + stride * 3] = w1 * sx;
array[offset + stride * 3 + 1] = h0 * sy;
offset += stride * 4;
}
};
ParticleBuffer.prototype.uploadPosition = function (children,startIndex, amount, array, stride, offset)
{
var spritePosition;
for (var i = 0; i < amount; i++) {
spritePosition = children[startIndex + i].position;
array[offset] = spritePosition.x;
array[offset + 1] = spritePosition.y;
array[offset + stride] = spritePosition.x;
array[offset + stride + 1] = spritePosition.y;
array[offset + stride * 2] = spritePosition.x;
array[offset + stride * 2 + 1] = spritePosition.y;
array[offset + stride * 3] = spritePosition.x;
array[offset + stride * 3 + 1] = spritePosition.y;
offset += stride * 4;
}
};
ParticleBuffer.prototype.uploadRotation = function (children,startIndex, amount, array, stride, offset)
{
var spriteRotation;
for (var i = 0; i < amount; i++) {
spriteRotation = children[startIndex + i].rotation;
array[offset] = spriteRotation;
array[offset + stride] = spriteRotation;
array[offset + stride * 2] = spriteRotation;
array[offset + stride * 3] = spriteRotation;
offset += stride * 4;
}
};
ParticleBuffer.prototype.uploadUvs = function (children,startIndex, amount, array, stride, offset)
{
var textureUvs;
for (var i = 0; i < amount; i++) {
textureUvs = children[startIndex + i]._texture._uvs;
if (textureUvs)
{
array[offset] = textureUvs.x0;
array[offset + 1] = textureUvs.y0;
array[offset + stride] = textureUvs.x1;
array[offset + stride + 1] = textureUvs.y1;
array[offset + stride * 2] = textureUvs.x2;
array[offset + stride * 2 + 1] = textureUvs.y2;
array[offset + stride * 3] = textureUvs.x3;
array[offset + stride * 3 + 1] = textureUvs.y3;
offset += stride * 4;
}
else
{
//TODO you know this can be easier!
array[offset] = 0;
array[offset + 1] = 0;
array[offset + stride] = 0;
array[offset + stride + 1] = 0;
array[offset + stride * 2] = 0;
array[offset + stride * 2 + 1] = 0;
array[offset + stride * 3] = 0;
array[offset + stride * 3 + 1] = 0;
offset += stride * 4;
}
}
};
ParticleBuffer.prototype.uploadAlpha = function (children,startIndex, amount, array, stride, offset)
{
var spriteAlpha;
for (var i = 0; i < amount; i++) {
spriteAlpha = children[startIndex + i].alpha;
array[offset] = spriteAlpha;
array[offset + stride] = spriteAlpha;
array[offset + stride * 2] = spriteAlpha;
array[offset + stride * 3] = spriteAlpha;
offset += stride * 4;
}
};
ParticleBuffer.prototype.uploadToBuffer = function (buffer, data, dataSize, amount)
{
var gl = this.gl;
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
if (this.currentBatchSize > ( this.size * 0.5 ) )
{
gl.bufferSubData(gl.ARRAY_BUFFER, 0, data);
}
else
{
var view = data.subarray(0, amount * dataSize);
gl.bufferSubData(gl.ARRAY_BUFFER, 0, view);
}
};
/**
* Starts a new sprite batch.
*
*/
ParticleBuffer.prototype.bind = function ()
{
var gl = this.gl;
var i, property;
gl.bindBuffer(gl.ARRAY_BUFFER, this.dynamicBuffer);
for (i = 0; i < this.dynamicProperties.length; i++)
{
property = this.dynamicProperties[i];
gl.vertexAttribPointer(property.attribute, property.size, gl.FLOAT, false, this.dynamicStride * 4, property.offset * 4);
}
gl.bindBuffer(gl.ARRAY_BUFFER, this.staticBuffer);
for (i = 0; i < this.staticProperties.length; i++)
{
property = this.staticProperties[i];
gl.vertexAttribPointer(property.attribute, property.size, gl.FLOAT, false, this.staticStride * 4, property.offset * 4);
}
};
/**
* Destroys the SpriteBatch.
*
*/
ParticleBuffer.prototype.destroy = function ()
{
//TODO implement this :) to busy making the fun bits..
};