diff --git a/src/core/particles/ParticleContainer.js b/src/core/particles/ParticleContainer.js index 5339d4c..9a85e36 100644 --- a/src/core/particles/ParticleContainer.js +++ b/src/core/particles/ParticleContainer.js @@ -23,9 +23,15 @@ * @class * @namespace PIXI */ -function ParticleContainer() +function ParticleContainer(size, properties) { Container.call(this); + + + this._properties = properties || [false, true, false, false, false];; + this._size = size || 15000; + this._buffers = null; + this._updateStatic = false; } ParticleContainer.prototype = Object.create(Container.prototype); @@ -65,6 +71,52 @@ }; +ParticleContainer.prototype.addChildAt = function (child, index) +{ + // prevent adding self as child + if (child === this) + { + return child; + } + + if (index >= 0 && index <= this.children.length) + { + if (child.parent) + { + child.parent.removeChild(child); + } + + child.parent = this; + + this.children.splice(index, 0, child); + + this._updateStatic = true; + + return child; + } + else + { + throw new Error(child + 'addChildAt: The index '+ index +' supplied is out of bounds ' + this.children.length); + } +}; + +/** + * Removes a child from the specified index position. + * + * @param index {Number} The index to get the child from + * @return {DisplayObject} The child that was removed. + */ +ParticleContainer.prototype.removeChildAt = function (index) +{ + var child = this.getChildAt(index); + + child.parent = null; + this.children.splice(index, 1); + this._updateStatic = true; + + return child; +}; + /** * Renders the object using the Canvas renderer * diff --git a/src/core/particles/ParticleContainer.js b/src/core/particles/ParticleContainer.js index 5339d4c..9a85e36 100644 --- a/src/core/particles/ParticleContainer.js +++ b/src/core/particles/ParticleContainer.js @@ -23,9 +23,15 @@ * @class * @namespace PIXI */ -function ParticleContainer() +function ParticleContainer(size, properties) { Container.call(this); + + + this._properties = properties || [false, true, false, false, false];; + this._size = size || 15000; + this._buffers = null; + this._updateStatic = false; } ParticleContainer.prototype = Object.create(Container.prototype); @@ -65,6 +71,52 @@ }; +ParticleContainer.prototype.addChildAt = function (child, index) +{ + // prevent adding self as child + if (child === this) + { + return child; + } + + if (index >= 0 && index <= this.children.length) + { + if (child.parent) + { + child.parent.removeChild(child); + } + + child.parent = this; + + this.children.splice(index, 0, child); + + this._updateStatic = true; + + return child; + } + else + { + throw new Error(child + 'addChildAt: The index '+ index +' supplied is out of bounds ' + this.children.length); + } +}; + +/** + * Removes a child from the specified index position. + * + * @param index {Number} The index to get the child from + * @return {DisplayObject} The child that was removed. + */ +ParticleContainer.prototype.removeChildAt = function (index) +{ + var child = this.getChildAt(index); + + child.parent = null; + this.children.splice(index, 1); + this._updateStatic = true; + + return child; +}; + /** * Renders the object using the Canvas renderer * diff --git a/src/core/particles/webgl/ParticleBuffer.js b/src/core/particles/webgl/ParticleBuffer.js index c707654..8bad65d 100644 --- a/src/core/particles/webgl/ParticleBuffer.js +++ b/src/core/particles/webgl/ParticleBuffer.js @@ -17,7 +17,7 @@ * @namespace PIXI * @param renderer {WebGLRenderer} The renderer this sprite batch works for. */ -function ParticleBuffer(gl, size, shader ) +function ParticleBuffer(gl, properties, size, shader ) { this.gl = gl; @@ -42,62 +42,21 @@ */ this.size = size; - this.verticiesData = { - attribute:shader.attributes.aVertexPosition, - dynamic:true, - size:2, - uploadFunction:this.uploadVerticies.bind(this), - offset:0 + this.dynamicProperties = []; + this.staticProperties = []; + + for (var i = 0; i < properties.length; i++) { + var property = properties[i]; + if(property.dynamic) + { + this.dynamicProperties.push(property); + } + else + { + this.staticProperties.push(property); + } }; - 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; @@ -132,12 +91,9 @@ { property = this.dynamicProperties[i]; - if(property.dynamic) - { - property.offset = dynamicOffset; - dynamicOffset += property.size; - this.dynamicStride += property.size; - } + property.offset = dynamicOffset; + dynamicOffset += property.size; + this.dynamicStride += property.size; } this.dynamicData = new Float32Array( this.size * this.dynamicStride * 4); @@ -155,12 +111,9 @@ { property = this.staticProperties[i]; - if(property.dynamic) - { - property.offset = staticOffset; - staticOffset += property.size; - this.staticStride += property.size; - } + property.offset = staticOffset; + staticOffset += property.size; + this.staticStride += property.size; } this.staticData = new Float32Array( this.size * this.staticStride * 4); @@ -171,214 +124,33 @@ }; -ParticleBuffer.prototype.upload = function(children, startIndex, amount, uploadStatic) +ParticleBuffer.prototype.uploadDynamic = function(children, startIndex, amount, uploadStatic) { - var i, property; var gl = this.gl; - for (i = 0; i < this.dynamicProperties.length; i++) + for (var i = 0; i < this.dynamicProperties.length; i++) { - property = this.dynamicProperties[i]; + var 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) +ParticleBuffer.prototype.uploadStatic = function(children, startIndex, amount, uploadStatic) { var gl = this.gl; - gl.bindBuffer(gl.ARRAY_BUFFER, buffer); + for (var i = 0; i < this.staticProperties.length; i++) + { + var property = this.staticProperties[i]; + property.uploadFunction(children, startIndex, amount, this.staticData, this.staticStride, property.offset); + } - 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); - } -}; + gl.bindBuffer(gl.ARRAY_BUFFER, this.staticBuffer); + gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.staticData); +} /** * Starts a new sprite batch. diff --git a/src/core/particles/ParticleContainer.js b/src/core/particles/ParticleContainer.js index 5339d4c..9a85e36 100644 --- a/src/core/particles/ParticleContainer.js +++ b/src/core/particles/ParticleContainer.js @@ -23,9 +23,15 @@ * @class * @namespace PIXI */ -function ParticleContainer() +function ParticleContainer(size, properties) { Container.call(this); + + + this._properties = properties || [false, true, false, false, false];; + this._size = size || 15000; + this._buffers = null; + this._updateStatic = false; } ParticleContainer.prototype = Object.create(Container.prototype); @@ -65,6 +71,52 @@ }; +ParticleContainer.prototype.addChildAt = function (child, index) +{ + // prevent adding self as child + if (child === this) + { + return child; + } + + if (index >= 0 && index <= this.children.length) + { + if (child.parent) + { + child.parent.removeChild(child); + } + + child.parent = this; + + this.children.splice(index, 0, child); + + this._updateStatic = true; + + return child; + } + else + { + throw new Error(child + 'addChildAt: The index '+ index +' supplied is out of bounds ' + this.children.length); + } +}; + +/** + * Removes a child from the specified index position. + * + * @param index {Number} The index to get the child from + * @return {DisplayObject} The child that was removed. + */ +ParticleContainer.prototype.removeChildAt = function (index) +{ + var child = this.getChildAt(index); + + child.parent = null; + this.children.splice(index, 1); + this._updateStatic = true; + + return child; +}; + /** * Renders the object using the Canvas renderer * diff --git a/src/core/particles/webgl/ParticleBuffer.js b/src/core/particles/webgl/ParticleBuffer.js index c707654..8bad65d 100644 --- a/src/core/particles/webgl/ParticleBuffer.js +++ b/src/core/particles/webgl/ParticleBuffer.js @@ -17,7 +17,7 @@ * @namespace PIXI * @param renderer {WebGLRenderer} The renderer this sprite batch works for. */ -function ParticleBuffer(gl, size, shader ) +function ParticleBuffer(gl, properties, size, shader ) { this.gl = gl; @@ -42,62 +42,21 @@ */ this.size = size; - this.verticiesData = { - attribute:shader.attributes.aVertexPosition, - dynamic:true, - size:2, - uploadFunction:this.uploadVerticies.bind(this), - offset:0 + this.dynamicProperties = []; + this.staticProperties = []; + + for (var i = 0; i < properties.length; i++) { + var property = properties[i]; + if(property.dynamic) + { + this.dynamicProperties.push(property); + } + else + { + this.staticProperties.push(property); + } }; - 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; @@ -132,12 +91,9 @@ { property = this.dynamicProperties[i]; - if(property.dynamic) - { - property.offset = dynamicOffset; - dynamicOffset += property.size; - this.dynamicStride += property.size; - } + property.offset = dynamicOffset; + dynamicOffset += property.size; + this.dynamicStride += property.size; } this.dynamicData = new Float32Array( this.size * this.dynamicStride * 4); @@ -155,12 +111,9 @@ { property = this.staticProperties[i]; - if(property.dynamic) - { - property.offset = staticOffset; - staticOffset += property.size; - this.staticStride += property.size; - } + property.offset = staticOffset; + staticOffset += property.size; + this.staticStride += property.size; } this.staticData = new Float32Array( this.size * this.staticStride * 4); @@ -171,214 +124,33 @@ }; -ParticleBuffer.prototype.upload = function(children, startIndex, amount, uploadStatic) +ParticleBuffer.prototype.uploadDynamic = function(children, startIndex, amount, uploadStatic) { - var i, property; var gl = this.gl; - for (i = 0; i < this.dynamicProperties.length; i++) + for (var i = 0; i < this.dynamicProperties.length; i++) { - property = this.dynamicProperties[i]; + var 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) +ParticleBuffer.prototype.uploadStatic = function(children, startIndex, amount, uploadStatic) { var gl = this.gl; - gl.bindBuffer(gl.ARRAY_BUFFER, buffer); + for (var i = 0; i < this.staticProperties.length; i++) + { + var property = this.staticProperties[i]; + property.uploadFunction(children, startIndex, amount, this.staticData, this.staticStride, property.offset); + } - 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); - } -}; + gl.bindBuffer(gl.ARRAY_BUFFER, this.staticBuffer); + gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.staticData); +} /** * Starts a new sprite batch. diff --git a/src/core/particles/webgl/ParticleRenderer.js b/src/core/particles/webgl/ParticleRenderer.js index ea55547..b8c7c21 100644 --- a/src/core/particles/webgl/ParticleRenderer.js +++ b/src/core/particles/webgl/ParticleRenderer.js @@ -4,18 +4,6 @@ ParticleBuffer = require('./ParticleBuffer'), math = require('../../math'); -var SpriteDataCache = function () -{ - this.rotation = 0; - this.pX = 0; - this.pY = 0; - this.texture = null; - this.sX = 0; - this.sY = 0; - this.alpha = 0; -}; - - /** * @author Mat Groves * @@ -45,7 +33,6 @@ * @member {number} */ this.size = 15000;//CONST.SPRITE_BATCH_SIZE; // 2000 is a nice balance between mobile / desktop - this.maxSprites = 200000; var numIndices = this.size * 6; @@ -68,30 +55,17 @@ } /** - * - * - * @member {number} - */ - this.currentBatchSize = 0; - - /** - * - * - * @member {Array} - */ - this.sprites = []; - this.spriteDataCache = []; - - /** * The default shader that is used if a sprite doesn't have a more specific one. * * @member {Shader} */ this.shader = null; - this.buffers = []; - this.tempMatrix = new math.Matrix(); + + + + } ParticleRenderer.prototype = Object.create(ObjectRenderer.prototype); @@ -121,131 +95,49 @@ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer); gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, this.indices, gl.STATIC_DRAW); - this.setSize(this.maxSprites); -}; -ParticleRenderer.prototype.setSize = function ( totalSize ) -{ - var gl = this.renderer.gl; - - var i; - - for (i = 0; i < totalSize; i += this.size) + this.properties = [ + //verticiesData { - this.buffers.push( new ParticleBuffer(gl, this.size, this.shader) ); - } - - for (i = 0; i < totalSize; i++) + attribute:this.shader.attributes.aVertexPosition, + dynamic:false, + size:2, + uploadFunction:this.uploadVerticies, + offset:0 + }, + // positionData { - this.spriteDataCache.push(new SpriteDataCache()); - } -}; - - -/** - * Renders the sprite object. - * - * @param sprite {Sprite} the sprite to render when using this Particle - */ -ParticleRenderer.prototype.render = function ( Particle ) -{ - var children = Particle.children; - - // if the uvs have not updated then no point rendering just yet! - //this.renderer.blendModeManager.setBlendMode(sprite.blendMode); - var gl = this.renderer.gl; - - var m = Particle.worldTransform.copy( this.tempMatrix ); - m.prepend( this.renderer.currentRenderTarget.projectionMatrix ); - - gl.uniformMatrix3fv(this.shader.uniforms.projectionMatrix._location, false, m.toArray(true)); - - this.sprites = children; - - this.vertDirty = 0; - - var uploadStatic = false; - - if(this._childCache !== children.length) + attribute:this.shader.attributes.aPositionCoord, + dynamic:true, + size:2, + uploadFunction:this.uploadPosition, + offset:0 + }, + // rotationData { - uploadStatic = true; - this._childCache = children.length; - } - - var j = 0; - - for (var i = 0; i < children.length; i+=this.size) + attribute:this.shader.attributes.aRotation, + dynamic:false, + size:1, + uploadFunction:this.uploadRotation, + offset:0 + }, + //u vsData { - var amount = ( children.length - i ); - if(amount > this.size) - { - amount = this.size; - } - - this.buffers[j++].upload(children, i, amount, uploadStatic); - } - - var baseTexture = children[0]._texture.baseTexture; - this.renderBatch(baseTexture, children.length, 0); -}; - - -ParticleRenderer.prototype.refresh = function(children) -{ - this.uploadVerticies(children); - - this.uploadRotation(children); - this.uploadUvs(children); - this.uploadAlpha(children); -}; - - -/** - * Draws the currently batches sprites. - * - * @private - * @param texture {Texture} - * @param size {number} - * @param startIndex {number} - */ -ParticleRenderer.prototype.renderBatch = function (texture, size, startIndex) -{ - if (size === 0) + attribute:this.shader.attributes.aTextureCoord, + dynamic:false, + size:2, + uploadFunction:this.uploadUvs, + offset:0 + }, + // alphaData { - return; - } + attribute:this.shader.attributes.aColor, + dynamic:false, + size:1, + uploadFunction:this.uploadAlpha, + offset:0 + }]; - var gl = this.renderer.gl; - - if (!texture._glTextures[gl.id]) - { - this.renderer.updateTexture(texture); - } - else - { - // bind the current texture - gl.bindTexture(gl.TEXTURE_2D, texture._glTextures[gl.id]); - } - - var j = 0; - for (var i = startIndex; i < size; i+=this.size) { - - this.buffers[j++].bind( this.shader ); - - - var amount = ( size - i) ; - if(amount > this.size) - { - amount = this.size; - } - // amount = 1; - // now draw those suckas! - gl.drawElements(gl.TRIANGLES, amount * 6, gl.UNSIGNED_SHORT, 0);//(startIndex % this.size) * 6 * 2); - } - - - // increment the draw count - this.renderer.drawCount++; }; /** @@ -265,35 +157,279 @@ var shader = this.shader; - this.renderer.shaderManager.setShader(shader); + this.renderer.shaderManager.setShader(shader); }; + +/** + * Renders the sprite object. + * + * @param sprite {Sprite} the sprite to render when using this Particle + */ +ParticleRenderer.prototype.render = function ( container ) +{ + var children = container.children, + totalChildren = children.length, + maxSize = container._size; + + if(totalChildren === 0) + { + return; + } + else if(totalChildren > maxSize) + { + totalChildren = maxSize; + } + + if(!container._buffers) + { + container._buffers = this.generateBuffers( container ); + } + + + + // if the uvs have not updated then no point rendering just yet! + //this.renderer.blendModeManager.setBlendMode(sprite.blendMode); + var gl = this.renderer.gl; + + var m = container.worldTransform.copy( this.tempMatrix ); + m.prepend( this.renderer.currentRenderTarget.projectionMatrix ); + gl.uniformMatrix3fv(this.shader.uniforms.projectionMatrix._location, false, m.toArray(true)); + + // if this variable is true then we will upload the static contents as well as the dynamic contens + var uploadStatic = container._updateStatic; + + // make sure the texture is bound.. + var baseTexture = children[0]._texture.baseTexture; + + if (!baseTexture._glTextures[gl.id]) + { + this.renderer.updateTexture(baseTexture); + if(!this.properties[0].dynamic || !this.properties[3].dynamic) + { + uploadStatic = true; + } + } + else + { + gl.bindTexture(gl.TEXTURE_2D, baseTexture._glTextures[gl.id]); + } + + // now lets upload and render the buffers.. + var j = 0; + for (var i = 0; i < totalChildren; i+=this.size) + { + var amount = ( totalChildren - i); + if(amount > this.size) + { + amount = this.size; + } + + var buffer = container._buffers[j++]; + + // we always upload the dynamic + buffer.uploadDynamic(children, i, amount); + + // we only upload the static content when we have to! + if(uploadStatic) + { + buffer.uploadStatic(children, i, amount); + } + + // bind the buffer + buffer.bind( this.shader ); + + // now draw those suckas! + gl.drawElements(gl.TRIANGLES, amount * 6, gl.UNSIGNED_SHORT, 0); + this.renderer.drawCount++; + } + + container._updateStatic = false; +}; + +ParticleRenderer.prototype.generateBuffers = function ( container ) +{ + var gl = this.renderer.gl; + var buffers = []; + var size = container._size; + + // update the properties to match the state of the container.. + for (var i = 0; i < container._properties.length; i++) + { + this.properties[i].dynamic = container._properties[i]; + } + + for (var i = 0; i < size; i += this.size) + { + buffers.push( new ParticleBuffer(gl, this.properties, this.size, this.shader) ); + } + + return buffers; +}; + + + +ParticleRenderer.prototype.uploadVerticies = function (children, startIndex, amount, array, stride, offset) +{ + 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; + } + + 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; + } + +}; + + +ParticleRenderer.prototype.uploadPosition = function (children,startIndex, amount, array, stride, offset) +{ + for (var i = 0; i < amount; i++) + { + var 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; + } + +}; + +ParticleRenderer.prototype.uploadRotation = function (children,startIndex, amount, array, stride, offset) +{ + for (var i = 0; i < amount; i++) + { + var 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; + } +}; + +ParticleRenderer.prototype.uploadUvs = function (children,startIndex, amount, array, stride, offset) +{ + for (var i = 0; i < amount; i++) + { + var 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; + } + } +}; + +ParticleRenderer.prototype.uploadAlpha = function (children,startIndex, amount, array, stride, offset) +{ + for (var i = 0; i < amount; i++) + { + var 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; + } +}; + + /** * Destroys the Particle. * */ ParticleRenderer.prototype.destroy = function () { - this.renderer.gl.deleteBuffer(this.vertexBuffer); - this.renderer.gl.deleteBuffer(this.indexBuffer); this.shader.destroy(); - this.renderer = null; - - this.vertices = null; - this.indices = null; - - this.vertexBuffer = null; - this.indexBuffer = null; - - this.drawing = false; - - this.textures = null; - this.blendModes = null; - this.shaders = null; - this.sprites = null; - this.shader = null; + //TODO implement this! }; diff --git a/src/core/particles/ParticleContainer.js b/src/core/particles/ParticleContainer.js index 5339d4c..9a85e36 100644 --- a/src/core/particles/ParticleContainer.js +++ b/src/core/particles/ParticleContainer.js @@ -23,9 +23,15 @@ * @class * @namespace PIXI */ -function ParticleContainer() +function ParticleContainer(size, properties) { Container.call(this); + + + this._properties = properties || [false, true, false, false, false];; + this._size = size || 15000; + this._buffers = null; + this._updateStatic = false; } ParticleContainer.prototype = Object.create(Container.prototype); @@ -65,6 +71,52 @@ }; +ParticleContainer.prototype.addChildAt = function (child, index) +{ + // prevent adding self as child + if (child === this) + { + return child; + } + + if (index >= 0 && index <= this.children.length) + { + if (child.parent) + { + child.parent.removeChild(child); + } + + child.parent = this; + + this.children.splice(index, 0, child); + + this._updateStatic = true; + + return child; + } + else + { + throw new Error(child + 'addChildAt: The index '+ index +' supplied is out of bounds ' + this.children.length); + } +}; + +/** + * Removes a child from the specified index position. + * + * @param index {Number} The index to get the child from + * @return {DisplayObject} The child that was removed. + */ +ParticleContainer.prototype.removeChildAt = function (index) +{ + var child = this.getChildAt(index); + + child.parent = null; + this.children.splice(index, 1); + this._updateStatic = true; + + return child; +}; + /** * Renders the object using the Canvas renderer * diff --git a/src/core/particles/webgl/ParticleBuffer.js b/src/core/particles/webgl/ParticleBuffer.js index c707654..8bad65d 100644 --- a/src/core/particles/webgl/ParticleBuffer.js +++ b/src/core/particles/webgl/ParticleBuffer.js @@ -17,7 +17,7 @@ * @namespace PIXI * @param renderer {WebGLRenderer} The renderer this sprite batch works for. */ -function ParticleBuffer(gl, size, shader ) +function ParticleBuffer(gl, properties, size, shader ) { this.gl = gl; @@ -42,62 +42,21 @@ */ this.size = size; - this.verticiesData = { - attribute:shader.attributes.aVertexPosition, - dynamic:true, - size:2, - uploadFunction:this.uploadVerticies.bind(this), - offset:0 + this.dynamicProperties = []; + this.staticProperties = []; + + for (var i = 0; i < properties.length; i++) { + var property = properties[i]; + if(property.dynamic) + { + this.dynamicProperties.push(property); + } + else + { + this.staticProperties.push(property); + } }; - 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; @@ -132,12 +91,9 @@ { property = this.dynamicProperties[i]; - if(property.dynamic) - { - property.offset = dynamicOffset; - dynamicOffset += property.size; - this.dynamicStride += property.size; - } + property.offset = dynamicOffset; + dynamicOffset += property.size; + this.dynamicStride += property.size; } this.dynamicData = new Float32Array( this.size * this.dynamicStride * 4); @@ -155,12 +111,9 @@ { property = this.staticProperties[i]; - if(property.dynamic) - { - property.offset = staticOffset; - staticOffset += property.size; - this.staticStride += property.size; - } + property.offset = staticOffset; + staticOffset += property.size; + this.staticStride += property.size; } this.staticData = new Float32Array( this.size * this.staticStride * 4); @@ -171,214 +124,33 @@ }; -ParticleBuffer.prototype.upload = function(children, startIndex, amount, uploadStatic) +ParticleBuffer.prototype.uploadDynamic = function(children, startIndex, amount, uploadStatic) { - var i, property; var gl = this.gl; - for (i = 0; i < this.dynamicProperties.length; i++) + for (var i = 0; i < this.dynamicProperties.length; i++) { - property = this.dynamicProperties[i]; + var 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) +ParticleBuffer.prototype.uploadStatic = function(children, startIndex, amount, uploadStatic) { var gl = this.gl; - gl.bindBuffer(gl.ARRAY_BUFFER, buffer); + for (var i = 0; i < this.staticProperties.length; i++) + { + var property = this.staticProperties[i]; + property.uploadFunction(children, startIndex, amount, this.staticData, this.staticStride, property.offset); + } - 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); - } -}; + gl.bindBuffer(gl.ARRAY_BUFFER, this.staticBuffer); + gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.staticData); +} /** * Starts a new sprite batch. diff --git a/src/core/particles/webgl/ParticleRenderer.js b/src/core/particles/webgl/ParticleRenderer.js index ea55547..b8c7c21 100644 --- a/src/core/particles/webgl/ParticleRenderer.js +++ b/src/core/particles/webgl/ParticleRenderer.js @@ -4,18 +4,6 @@ ParticleBuffer = require('./ParticleBuffer'), math = require('../../math'); -var SpriteDataCache = function () -{ - this.rotation = 0; - this.pX = 0; - this.pY = 0; - this.texture = null; - this.sX = 0; - this.sY = 0; - this.alpha = 0; -}; - - /** * @author Mat Groves * @@ -45,7 +33,6 @@ * @member {number} */ this.size = 15000;//CONST.SPRITE_BATCH_SIZE; // 2000 is a nice balance between mobile / desktop - this.maxSprites = 200000; var numIndices = this.size * 6; @@ -68,30 +55,17 @@ } /** - * - * - * @member {number} - */ - this.currentBatchSize = 0; - - /** - * - * - * @member {Array} - */ - this.sprites = []; - this.spriteDataCache = []; - - /** * The default shader that is used if a sprite doesn't have a more specific one. * * @member {Shader} */ this.shader = null; - this.buffers = []; - this.tempMatrix = new math.Matrix(); + + + + } ParticleRenderer.prototype = Object.create(ObjectRenderer.prototype); @@ -121,131 +95,49 @@ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer); gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, this.indices, gl.STATIC_DRAW); - this.setSize(this.maxSprites); -}; -ParticleRenderer.prototype.setSize = function ( totalSize ) -{ - var gl = this.renderer.gl; - - var i; - - for (i = 0; i < totalSize; i += this.size) + this.properties = [ + //verticiesData { - this.buffers.push( new ParticleBuffer(gl, this.size, this.shader) ); - } - - for (i = 0; i < totalSize; i++) + attribute:this.shader.attributes.aVertexPosition, + dynamic:false, + size:2, + uploadFunction:this.uploadVerticies, + offset:0 + }, + // positionData { - this.spriteDataCache.push(new SpriteDataCache()); - } -}; - - -/** - * Renders the sprite object. - * - * @param sprite {Sprite} the sprite to render when using this Particle - */ -ParticleRenderer.prototype.render = function ( Particle ) -{ - var children = Particle.children; - - // if the uvs have not updated then no point rendering just yet! - //this.renderer.blendModeManager.setBlendMode(sprite.blendMode); - var gl = this.renderer.gl; - - var m = Particle.worldTransform.copy( this.tempMatrix ); - m.prepend( this.renderer.currentRenderTarget.projectionMatrix ); - - gl.uniformMatrix3fv(this.shader.uniforms.projectionMatrix._location, false, m.toArray(true)); - - this.sprites = children; - - this.vertDirty = 0; - - var uploadStatic = false; - - if(this._childCache !== children.length) + attribute:this.shader.attributes.aPositionCoord, + dynamic:true, + size:2, + uploadFunction:this.uploadPosition, + offset:0 + }, + // rotationData { - uploadStatic = true; - this._childCache = children.length; - } - - var j = 0; - - for (var i = 0; i < children.length; i+=this.size) + attribute:this.shader.attributes.aRotation, + dynamic:false, + size:1, + uploadFunction:this.uploadRotation, + offset:0 + }, + //u vsData { - var amount = ( children.length - i ); - if(amount > this.size) - { - amount = this.size; - } - - this.buffers[j++].upload(children, i, amount, uploadStatic); - } - - var baseTexture = children[0]._texture.baseTexture; - this.renderBatch(baseTexture, children.length, 0); -}; - - -ParticleRenderer.prototype.refresh = function(children) -{ - this.uploadVerticies(children); - - this.uploadRotation(children); - this.uploadUvs(children); - this.uploadAlpha(children); -}; - - -/** - * Draws the currently batches sprites. - * - * @private - * @param texture {Texture} - * @param size {number} - * @param startIndex {number} - */ -ParticleRenderer.prototype.renderBatch = function (texture, size, startIndex) -{ - if (size === 0) + attribute:this.shader.attributes.aTextureCoord, + dynamic:false, + size:2, + uploadFunction:this.uploadUvs, + offset:0 + }, + // alphaData { - return; - } + attribute:this.shader.attributes.aColor, + dynamic:false, + size:1, + uploadFunction:this.uploadAlpha, + offset:0 + }]; - var gl = this.renderer.gl; - - if (!texture._glTextures[gl.id]) - { - this.renderer.updateTexture(texture); - } - else - { - // bind the current texture - gl.bindTexture(gl.TEXTURE_2D, texture._glTextures[gl.id]); - } - - var j = 0; - for (var i = startIndex; i < size; i+=this.size) { - - this.buffers[j++].bind( this.shader ); - - - var amount = ( size - i) ; - if(amount > this.size) - { - amount = this.size; - } - // amount = 1; - // now draw those suckas! - gl.drawElements(gl.TRIANGLES, amount * 6, gl.UNSIGNED_SHORT, 0);//(startIndex % this.size) * 6 * 2); - } - - - // increment the draw count - this.renderer.drawCount++; }; /** @@ -265,35 +157,279 @@ var shader = this.shader; - this.renderer.shaderManager.setShader(shader); + this.renderer.shaderManager.setShader(shader); }; + +/** + * Renders the sprite object. + * + * @param sprite {Sprite} the sprite to render when using this Particle + */ +ParticleRenderer.prototype.render = function ( container ) +{ + var children = container.children, + totalChildren = children.length, + maxSize = container._size; + + if(totalChildren === 0) + { + return; + } + else if(totalChildren > maxSize) + { + totalChildren = maxSize; + } + + if(!container._buffers) + { + container._buffers = this.generateBuffers( container ); + } + + + + // if the uvs have not updated then no point rendering just yet! + //this.renderer.blendModeManager.setBlendMode(sprite.blendMode); + var gl = this.renderer.gl; + + var m = container.worldTransform.copy( this.tempMatrix ); + m.prepend( this.renderer.currentRenderTarget.projectionMatrix ); + gl.uniformMatrix3fv(this.shader.uniforms.projectionMatrix._location, false, m.toArray(true)); + + // if this variable is true then we will upload the static contents as well as the dynamic contens + var uploadStatic = container._updateStatic; + + // make sure the texture is bound.. + var baseTexture = children[0]._texture.baseTexture; + + if (!baseTexture._glTextures[gl.id]) + { + this.renderer.updateTexture(baseTexture); + if(!this.properties[0].dynamic || !this.properties[3].dynamic) + { + uploadStatic = true; + } + } + else + { + gl.bindTexture(gl.TEXTURE_2D, baseTexture._glTextures[gl.id]); + } + + // now lets upload and render the buffers.. + var j = 0; + for (var i = 0; i < totalChildren; i+=this.size) + { + var amount = ( totalChildren - i); + if(amount > this.size) + { + amount = this.size; + } + + var buffer = container._buffers[j++]; + + // we always upload the dynamic + buffer.uploadDynamic(children, i, amount); + + // we only upload the static content when we have to! + if(uploadStatic) + { + buffer.uploadStatic(children, i, amount); + } + + // bind the buffer + buffer.bind( this.shader ); + + // now draw those suckas! + gl.drawElements(gl.TRIANGLES, amount * 6, gl.UNSIGNED_SHORT, 0); + this.renderer.drawCount++; + } + + container._updateStatic = false; +}; + +ParticleRenderer.prototype.generateBuffers = function ( container ) +{ + var gl = this.renderer.gl; + var buffers = []; + var size = container._size; + + // update the properties to match the state of the container.. + for (var i = 0; i < container._properties.length; i++) + { + this.properties[i].dynamic = container._properties[i]; + } + + for (var i = 0; i < size; i += this.size) + { + buffers.push( new ParticleBuffer(gl, this.properties, this.size, this.shader) ); + } + + return buffers; +}; + + + +ParticleRenderer.prototype.uploadVerticies = function (children, startIndex, amount, array, stride, offset) +{ + 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; + } + + 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; + } + +}; + + +ParticleRenderer.prototype.uploadPosition = function (children,startIndex, amount, array, stride, offset) +{ + for (var i = 0; i < amount; i++) + { + var 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; + } + +}; + +ParticleRenderer.prototype.uploadRotation = function (children,startIndex, amount, array, stride, offset) +{ + for (var i = 0; i < amount; i++) + { + var 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; + } +}; + +ParticleRenderer.prototype.uploadUvs = function (children,startIndex, amount, array, stride, offset) +{ + for (var i = 0; i < amount; i++) + { + var 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; + } + } +}; + +ParticleRenderer.prototype.uploadAlpha = function (children,startIndex, amount, array, stride, offset) +{ + for (var i = 0; i < amount; i++) + { + var 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; + } +}; + + /** * Destroys the Particle. * */ ParticleRenderer.prototype.destroy = function () { - this.renderer.gl.deleteBuffer(this.vertexBuffer); - this.renderer.gl.deleteBuffer(this.indexBuffer); this.shader.destroy(); - this.renderer = null; - - this.vertices = null; - this.indices = null; - - this.vertexBuffer = null; - this.indexBuffer = null; - - this.drawing = false; - - this.textures = null; - this.blendModes = null; - this.shaders = null; - this.sprites = null; - this.shader = null; + //TODO implement this! }; diff --git a/src/core/renderers/SystemRenderer.js b/src/core/renderers/SystemRenderer.js index bb0b894..b271eac 100644 --- a/src/core/renderers/SystemRenderer.js +++ b/src/core/renderers/SystemRenderer.js @@ -130,7 +130,7 @@ * @member {number} * @private */ - this._backgroundColor = 0x000000; + this._backgroundColor = 0xFFFFFF; /** * The background color as an [R, G, B] array. @@ -138,7 +138,7 @@ * @member {number[]} * @private */ - this._backgroundColorRgb = [0, 0, 0]; + this._backgroundColorRgb = [1, 1, 1]; /** * The background color as a string.