diff --git a/src/particles/ParticleContainer.js b/src/particles/ParticleContainer.js index 1c725d2..60f7fce 100644 --- a/src/particles/ParticleContainer.js +++ b/src/particles/ParticleContainer.js @@ -149,7 +149,8 @@ this._properties[1] = 'position' in properties ? !!properties.position : this._properties[1]; this._properties[2] = 'rotation' in properties ? !!properties.rotation : this._properties[2]; this._properties[3] = 'uvs' in properties ? !!properties.uvs : this._properties[3]; - this._properties[4] = 'alpha' in properties ? !!properties.alpha : this._properties[4]; + this._properties[4] = 'alpha' in properties || 'tint' in properties + ? !!properties.alpha || !!properties.tint : this._properties[4]; } } diff --git a/src/particles/ParticleContainer.js b/src/particles/ParticleContainer.js index 1c725d2..60f7fce 100644 --- a/src/particles/ParticleContainer.js +++ b/src/particles/ParticleContainer.js @@ -149,7 +149,8 @@ this._properties[1] = 'position' in properties ? !!properties.position : this._properties[1]; this._properties[2] = 'rotation' in properties ? !!properties.rotation : this._properties[2]; this._properties[3] = 'uvs' in properties ? !!properties.uvs : this._properties[3]; - this._properties[4] = 'alpha' in properties ? !!properties.alpha : this._properties[4]; + this._properties[4] = 'alpha' in properties || 'tint' in properties + ? !!properties.alpha || !!properties.tint : this._properties[4]; } } diff --git a/src/particles/webgl/ParticleBuffer.js b/src/particles/webgl/ParticleBuffer.js index bd8e243..0d41f66 100644 --- a/src/particles/webgl/ParticleBuffer.js +++ b/src/particles/webgl/ParticleBuffer.js @@ -38,20 +38,6 @@ this.gl = gl; /** - * Size of a single vertex. - * - * @member {number} - */ - this.vertSize = 2; - - /** - * Size of a single vertex in bytes. - * - * @member {number} - */ - this.vertByteSize = this.vertSize * 4; - - /** * The number of particles the buffer can hold * * @member {number} @@ -82,6 +68,7 @@ attribute: property.attribute, size: property.size, uploadFunction: property.uploadFunction, + unsignedByte: property.unsignedByte, offset: property.offset, }; @@ -98,10 +85,12 @@ this.staticStride = 0; this.staticBuffer = null; this.staticData = null; + this.staticDataUint32 = null; this.dynamicStride = 0; this.dynamicBuffer = null; this.dynamicData = null; + this.dynamicDataUint32 = null; this.initBuffers(); } @@ -135,8 +124,11 @@ this.dynamicStride += property.size; } - this.dynamicData = new Float32Array(this.size * this.dynamicStride * 4); - this.dynamicBuffer = glCore.GLBuffer.createVertexBuffer(gl, this.dynamicData, gl.STREAM_DRAW); + const dynBuffer = new ArrayBuffer(this.size * this.dynamicStride * 4 * 4); + + this.dynamicData = new Float32Array(dynBuffer); + this.dynamicDataUint32 = new Uint32Array(dynBuffer); + this.dynamicBuffer = glCore.GLBuffer.createVertexBuffer(gl, dynBuffer, gl.STREAM_DRAW); // static // let staticOffset = 0; @@ -152,8 +144,11 @@ this.staticStride += property.size; } - this.staticData = new Float32Array(this.size * this.staticStride * 4); - this.staticBuffer = glCore.GLBuffer.createVertexBuffer(gl, this.staticData, gl.STATIC_DRAW); + const statBuffer = new ArrayBuffer(this.size * this.staticStride * 4 * 4); + + this.staticData = new Float32Array(statBuffer); + this.staticDataUint32 = new Uint32Array(statBuffer); + this.staticBuffer = glCore.GLBuffer.createVertexBuffer(gl, statBuffer, gl.STATIC_DRAW); this.vao = new glCore.VertexArrayObject(gl) .addIndex(this.indexBuffer); @@ -162,28 +157,56 @@ { const property = this.dynamicProperties[i]; - this.vao.addAttribute( - this.dynamicBuffer, - property.attribute, - gl.FLOAT, - false, - this.dynamicStride * 4, - property.offset * 4 - ); + if (property.unsignedByte) + { + this.vao.addAttribute( + this.dynamicBuffer, + property.attribute, + gl.UNSIGNED_BYTE, + true, + this.dynamicStride * 4, + property.offset * 4 + ); + } + else + { + this.vao.addAttribute( + this.dynamicBuffer, + property.attribute, + gl.FLOAT, + false, + this.dynamicStride * 4, + property.offset * 4 + ); + } } for (let i = 0; i < this.staticProperties.length; ++i) { const property = this.staticProperties[i]; - this.vao.addAttribute( - this.staticBuffer, - property.attribute, - gl.FLOAT, - false, - this.staticStride * 4, - property.offset * 4 - ); + if (property.unsignedByte) + { + this.vao.addAttribute( + this.staticBuffer, + property.attribute, + gl.UNSIGNED_BYTE, + true, + this.staticStride * 4, + property.offset * 4 + ); + } + else + { + this.vao.addAttribute( + this.staticBuffer, + property.attribute, + gl.FLOAT, + false, + this.staticStride * 4, + property.offset * 4 + ); + } } } @@ -200,7 +223,9 @@ { const property = this.dynamicProperties[i]; - property.uploadFunction(children, startIndex, amount, this.dynamicData, this.dynamicStride, property.offset); + property.uploadFunction(children, startIndex, amount, + property.unsignedByte ? this.dynamicDataUint32 : this.dynamicData, + this.dynamicStride, property.offset); } this.dynamicBuffer.upload(); @@ -219,7 +244,9 @@ { const property = this.staticProperties[i]; - property.uploadFunction(children, startIndex, amount, this.staticData, this.staticStride, property.offset); + property.uploadFunction(children, startIndex, amount, + property.unsignedByte ? this.staticDataUint32 : this.staticData, + this.staticStride, property.offset); } this.staticBuffer.upload(); diff --git a/src/particles/ParticleContainer.js b/src/particles/ParticleContainer.js index 1c725d2..60f7fce 100644 --- a/src/particles/ParticleContainer.js +++ b/src/particles/ParticleContainer.js @@ -149,7 +149,8 @@ this._properties[1] = 'position' in properties ? !!properties.position : this._properties[1]; this._properties[2] = 'rotation' in properties ? !!properties.rotation : this._properties[2]; this._properties[3] = 'uvs' in properties ? !!properties.uvs : this._properties[3]; - this._properties[4] = 'alpha' in properties ? !!properties.alpha : this._properties[4]; + this._properties[4] = 'alpha' in properties || 'tint' in properties + ? !!properties.alpha || !!properties.tint : this._properties[4]; } } diff --git a/src/particles/webgl/ParticleBuffer.js b/src/particles/webgl/ParticleBuffer.js index bd8e243..0d41f66 100644 --- a/src/particles/webgl/ParticleBuffer.js +++ b/src/particles/webgl/ParticleBuffer.js @@ -38,20 +38,6 @@ this.gl = gl; /** - * Size of a single vertex. - * - * @member {number} - */ - this.vertSize = 2; - - /** - * Size of a single vertex in bytes. - * - * @member {number} - */ - this.vertByteSize = this.vertSize * 4; - - /** * The number of particles the buffer can hold * * @member {number} @@ -82,6 +68,7 @@ attribute: property.attribute, size: property.size, uploadFunction: property.uploadFunction, + unsignedByte: property.unsignedByte, offset: property.offset, }; @@ -98,10 +85,12 @@ this.staticStride = 0; this.staticBuffer = null; this.staticData = null; + this.staticDataUint32 = null; this.dynamicStride = 0; this.dynamicBuffer = null; this.dynamicData = null; + this.dynamicDataUint32 = null; this.initBuffers(); } @@ -135,8 +124,11 @@ this.dynamicStride += property.size; } - this.dynamicData = new Float32Array(this.size * this.dynamicStride * 4); - this.dynamicBuffer = glCore.GLBuffer.createVertexBuffer(gl, this.dynamicData, gl.STREAM_DRAW); + const dynBuffer = new ArrayBuffer(this.size * this.dynamicStride * 4 * 4); + + this.dynamicData = new Float32Array(dynBuffer); + this.dynamicDataUint32 = new Uint32Array(dynBuffer); + this.dynamicBuffer = glCore.GLBuffer.createVertexBuffer(gl, dynBuffer, gl.STREAM_DRAW); // static // let staticOffset = 0; @@ -152,8 +144,11 @@ this.staticStride += property.size; } - this.staticData = new Float32Array(this.size * this.staticStride * 4); - this.staticBuffer = glCore.GLBuffer.createVertexBuffer(gl, this.staticData, gl.STATIC_DRAW); + const statBuffer = new ArrayBuffer(this.size * this.staticStride * 4 * 4); + + this.staticData = new Float32Array(statBuffer); + this.staticDataUint32 = new Uint32Array(statBuffer); + this.staticBuffer = glCore.GLBuffer.createVertexBuffer(gl, statBuffer, gl.STATIC_DRAW); this.vao = new glCore.VertexArrayObject(gl) .addIndex(this.indexBuffer); @@ -162,28 +157,56 @@ { const property = this.dynamicProperties[i]; - this.vao.addAttribute( - this.dynamicBuffer, - property.attribute, - gl.FLOAT, - false, - this.dynamicStride * 4, - property.offset * 4 - ); + if (property.unsignedByte) + { + this.vao.addAttribute( + this.dynamicBuffer, + property.attribute, + gl.UNSIGNED_BYTE, + true, + this.dynamicStride * 4, + property.offset * 4 + ); + } + else + { + this.vao.addAttribute( + this.dynamicBuffer, + property.attribute, + gl.FLOAT, + false, + this.dynamicStride * 4, + property.offset * 4 + ); + } } for (let i = 0; i < this.staticProperties.length; ++i) { const property = this.staticProperties[i]; - this.vao.addAttribute( - this.staticBuffer, - property.attribute, - gl.FLOAT, - false, - this.staticStride * 4, - property.offset * 4 - ); + if (property.unsignedByte) + { + this.vao.addAttribute( + this.staticBuffer, + property.attribute, + gl.UNSIGNED_BYTE, + true, + this.staticStride * 4, + property.offset * 4 + ); + } + else + { + this.vao.addAttribute( + this.staticBuffer, + property.attribute, + gl.FLOAT, + false, + this.staticStride * 4, + property.offset * 4 + ); + } } } @@ -200,7 +223,9 @@ { const property = this.dynamicProperties[i]; - property.uploadFunction(children, startIndex, amount, this.dynamicData, this.dynamicStride, property.offset); + property.uploadFunction(children, startIndex, amount, + property.unsignedByte ? this.dynamicDataUint32 : this.dynamicData, + this.dynamicStride, property.offset); } this.dynamicBuffer.upload(); @@ -219,7 +244,9 @@ { const property = this.staticProperties[i]; - property.uploadFunction(children, startIndex, amount, this.staticData, this.staticStride, property.offset); + property.uploadFunction(children, startIndex, amount, + property.unsignedByte ? this.staticDataUint32 : this.staticData, + this.staticStride, property.offset); } this.staticBuffer.upload(); diff --git a/src/particles/webgl/ParticleRenderer.js b/src/particles/webgl/ParticleRenderer.js index 1b39985..c1b2d98 100644 --- a/src/particles/webgl/ParticleRenderer.js +++ b/src/particles/webgl/ParticleRenderer.js @@ -1,6 +1,7 @@ import * as core from '../../core'; import ParticleShader from './ParticleShader'; import ParticleBuffer from './ParticleBuffer'; +import { premultiplyTint } from '../../core/utils'; /** * @author Mat Groves @@ -94,11 +95,12 @@ uploadFunction: this.uploadUvs, offset: 0, }, - // alphaData + // tintData { attribute: this.shader.attributes.aColor, size: 1, - uploadFunction: this.uploadAlpha, + unsignedByte: true, + uploadFunction: this.uploadTint, offset: 0, }, ]; @@ -387,16 +389,21 @@ * @param {number} stride - Stride to use for iteration. * @param {number} offset - Offset to start at. */ - uploadAlpha(children, startIndex, amount, array, stride, offset) + uploadTint(children, startIndex, amount, array, stride, offset) { - for (let i = 0; i < amount; i++) + for (let i = 0; i < amount; ++i) { - const spriteAlpha = children[startIndex + i].alpha; + const sprite = children[startIndex + i]; + const premultiplied = sprite._texture.baseTexture.premultipliedAlpha; + const alpha = sprite.alpha; + // we dont call extra function if alpha is 1.0, that's faster + const argb = alpha < 1.0 && premultiplied ? premultiplyTint(sprite._tintRGB, alpha) + : sprite._tintRGB + (alpha * 255 << 24); - array[offset] = spriteAlpha; - array[offset + stride] = spriteAlpha; - array[offset + (stride * 2)] = spriteAlpha; - array[offset + (stride * 3)] = spriteAlpha; + array[offset] = argb; + array[offset + stride] = argb; + array[offset + (stride * 2)] = argb; + array[offset + (stride * 3)] = argb; offset += stride * 4; } diff --git a/src/particles/ParticleContainer.js b/src/particles/ParticleContainer.js index 1c725d2..60f7fce 100644 --- a/src/particles/ParticleContainer.js +++ b/src/particles/ParticleContainer.js @@ -149,7 +149,8 @@ this._properties[1] = 'position' in properties ? !!properties.position : this._properties[1]; this._properties[2] = 'rotation' in properties ? !!properties.rotation : this._properties[2]; this._properties[3] = 'uvs' in properties ? !!properties.uvs : this._properties[3]; - this._properties[4] = 'alpha' in properties ? !!properties.alpha : this._properties[4]; + this._properties[4] = 'alpha' in properties || 'tint' in properties + ? !!properties.alpha || !!properties.tint : this._properties[4]; } } diff --git a/src/particles/webgl/ParticleBuffer.js b/src/particles/webgl/ParticleBuffer.js index bd8e243..0d41f66 100644 --- a/src/particles/webgl/ParticleBuffer.js +++ b/src/particles/webgl/ParticleBuffer.js @@ -38,20 +38,6 @@ this.gl = gl; /** - * Size of a single vertex. - * - * @member {number} - */ - this.vertSize = 2; - - /** - * Size of a single vertex in bytes. - * - * @member {number} - */ - this.vertByteSize = this.vertSize * 4; - - /** * The number of particles the buffer can hold * * @member {number} @@ -82,6 +68,7 @@ attribute: property.attribute, size: property.size, uploadFunction: property.uploadFunction, + unsignedByte: property.unsignedByte, offset: property.offset, }; @@ -98,10 +85,12 @@ this.staticStride = 0; this.staticBuffer = null; this.staticData = null; + this.staticDataUint32 = null; this.dynamicStride = 0; this.dynamicBuffer = null; this.dynamicData = null; + this.dynamicDataUint32 = null; this.initBuffers(); } @@ -135,8 +124,11 @@ this.dynamicStride += property.size; } - this.dynamicData = new Float32Array(this.size * this.dynamicStride * 4); - this.dynamicBuffer = glCore.GLBuffer.createVertexBuffer(gl, this.dynamicData, gl.STREAM_DRAW); + const dynBuffer = new ArrayBuffer(this.size * this.dynamicStride * 4 * 4); + + this.dynamicData = new Float32Array(dynBuffer); + this.dynamicDataUint32 = new Uint32Array(dynBuffer); + this.dynamicBuffer = glCore.GLBuffer.createVertexBuffer(gl, dynBuffer, gl.STREAM_DRAW); // static // let staticOffset = 0; @@ -152,8 +144,11 @@ this.staticStride += property.size; } - this.staticData = new Float32Array(this.size * this.staticStride * 4); - this.staticBuffer = glCore.GLBuffer.createVertexBuffer(gl, this.staticData, gl.STATIC_DRAW); + const statBuffer = new ArrayBuffer(this.size * this.staticStride * 4 * 4); + + this.staticData = new Float32Array(statBuffer); + this.staticDataUint32 = new Uint32Array(statBuffer); + this.staticBuffer = glCore.GLBuffer.createVertexBuffer(gl, statBuffer, gl.STATIC_DRAW); this.vao = new glCore.VertexArrayObject(gl) .addIndex(this.indexBuffer); @@ -162,28 +157,56 @@ { const property = this.dynamicProperties[i]; - this.vao.addAttribute( - this.dynamicBuffer, - property.attribute, - gl.FLOAT, - false, - this.dynamicStride * 4, - property.offset * 4 - ); + if (property.unsignedByte) + { + this.vao.addAttribute( + this.dynamicBuffer, + property.attribute, + gl.UNSIGNED_BYTE, + true, + this.dynamicStride * 4, + property.offset * 4 + ); + } + else + { + this.vao.addAttribute( + this.dynamicBuffer, + property.attribute, + gl.FLOAT, + false, + this.dynamicStride * 4, + property.offset * 4 + ); + } } for (let i = 0; i < this.staticProperties.length; ++i) { const property = this.staticProperties[i]; - this.vao.addAttribute( - this.staticBuffer, - property.attribute, - gl.FLOAT, - false, - this.staticStride * 4, - property.offset * 4 - ); + if (property.unsignedByte) + { + this.vao.addAttribute( + this.staticBuffer, + property.attribute, + gl.UNSIGNED_BYTE, + true, + this.staticStride * 4, + property.offset * 4 + ); + } + else + { + this.vao.addAttribute( + this.staticBuffer, + property.attribute, + gl.FLOAT, + false, + this.staticStride * 4, + property.offset * 4 + ); + } } } @@ -200,7 +223,9 @@ { const property = this.dynamicProperties[i]; - property.uploadFunction(children, startIndex, amount, this.dynamicData, this.dynamicStride, property.offset); + property.uploadFunction(children, startIndex, amount, + property.unsignedByte ? this.dynamicDataUint32 : this.dynamicData, + this.dynamicStride, property.offset); } this.dynamicBuffer.upload(); @@ -219,7 +244,9 @@ { const property = this.staticProperties[i]; - property.uploadFunction(children, startIndex, amount, this.staticData, this.staticStride, property.offset); + property.uploadFunction(children, startIndex, amount, + property.unsignedByte ? this.staticDataUint32 : this.staticData, + this.staticStride, property.offset); } this.staticBuffer.upload(); diff --git a/src/particles/webgl/ParticleRenderer.js b/src/particles/webgl/ParticleRenderer.js index 1b39985..c1b2d98 100644 --- a/src/particles/webgl/ParticleRenderer.js +++ b/src/particles/webgl/ParticleRenderer.js @@ -1,6 +1,7 @@ import * as core from '../../core'; import ParticleShader from './ParticleShader'; import ParticleBuffer from './ParticleBuffer'; +import { premultiplyTint } from '../../core/utils'; /** * @author Mat Groves @@ -94,11 +95,12 @@ uploadFunction: this.uploadUvs, offset: 0, }, - // alphaData + // tintData { attribute: this.shader.attributes.aColor, size: 1, - uploadFunction: this.uploadAlpha, + unsignedByte: true, + uploadFunction: this.uploadTint, offset: 0, }, ]; @@ -387,16 +389,21 @@ * @param {number} stride - Stride to use for iteration. * @param {number} offset - Offset to start at. */ - uploadAlpha(children, startIndex, amount, array, stride, offset) + uploadTint(children, startIndex, amount, array, stride, offset) { - for (let i = 0; i < amount; i++) + for (let i = 0; i < amount; ++i) { - const spriteAlpha = children[startIndex + i].alpha; + const sprite = children[startIndex + i]; + const premultiplied = sprite._texture.baseTexture.premultipliedAlpha; + const alpha = sprite.alpha; + // we dont call extra function if alpha is 1.0, that's faster + const argb = alpha < 1.0 && premultiplied ? premultiplyTint(sprite._tintRGB, alpha) + : sprite._tintRGB + (alpha * 255 << 24); - array[offset] = spriteAlpha; - array[offset + stride] = spriteAlpha; - array[offset + (stride * 2)] = spriteAlpha; - array[offset + (stride * 3)] = spriteAlpha; + array[offset] = argb; + array[offset + stride] = argb; + array[offset + (stride * 2)] = argb; + array[offset + (stride * 3)] = argb; offset += stride * 4; } diff --git a/src/particles/webgl/ParticleShader.js b/src/particles/webgl/ParticleShader.js index 4361623..b3584fe 100644 --- a/src/particles/webgl/ParticleShader.js +++ b/src/particles/webgl/ParticleShader.js @@ -18,16 +18,17 @@ [ 'attribute vec2 aVertexPosition;', 'attribute vec2 aTextureCoord;', - 'attribute float aColor;', + 'attribute vec4 aColor;', 'attribute vec2 aPositionCoord;', 'attribute vec2 aScale;', 'attribute float aRotation;', 'uniform mat3 projectionMatrix;', + 'uniform vec4 uColor;', 'varying vec2 vTextureCoord;', - 'varying float vColor;', + 'varying vec4 vColor;', 'void main(void){', ' vec2 v = aVertexPosition;', @@ -39,19 +40,18 @@ ' gl_Position = vec4((projectionMatrix * vec3(v, 1.0)).xy, 0.0, 1.0);', ' vTextureCoord = aTextureCoord;', - ' vColor = aColor;', + ' vColor = aColor * uColor;', '}', ].join('\n'), // hello [ 'varying vec2 vTextureCoord;', - 'varying float vColor;', + 'varying vec4 vColor;', 'uniform sampler2D uSampler;', - 'uniform vec4 uColor;', 'void main(void){', - ' vec4 color = texture2D(uSampler, vTextureCoord) * vColor * uColor;', + ' vec4 color = texture2D(uSampler, vTextureCoord) * vColor;', ' if (color.a == 0.0) discard;', ' gl_FragColor = color;', '}',