diff --git a/src/core/index.js b/src/core/index.js index 1d0a398..4fc777d 100644 --- a/src/core/index.js +++ b/src/core/index.js @@ -24,6 +24,7 @@ Sprite: require('./sprites/Sprite'), SpriteBatch: require('./sprites/SpriteBatch'), SpriteRenderer: require('./sprites/webgl/SpriteRenderer'), + SpriteBatchRenderer: require('./sprites/webgl/SpriteBatchRenderer'), // primitives Graphics: require('./graphics/Graphics'), @@ -43,6 +44,7 @@ // renderers - webgl WebGLRenderer: require('./renderers/webgl/WebGLRenderer'), + WebGLShaderManager: require('./renderers/webgl/managers/WebGLShaderManager'), Shader: require('./renderers/webgl/shaders/Shader'), /** diff --git a/src/core/index.js b/src/core/index.js index 1d0a398..4fc777d 100644 --- a/src/core/index.js +++ b/src/core/index.js @@ -24,6 +24,7 @@ Sprite: require('./sprites/Sprite'), SpriteBatch: require('./sprites/SpriteBatch'), SpriteRenderer: require('./sprites/webgl/SpriteRenderer'), + SpriteBatchRenderer: require('./sprites/webgl/SpriteBatchRenderer'), // primitives Graphics: require('./graphics/Graphics'), @@ -43,6 +44,7 @@ // renderers - webgl WebGLRenderer: require('./renderers/webgl/WebGLRenderer'), + WebGLShaderManager: require('./renderers/webgl/managers/WebGLShaderManager'), Shader: require('./renderers/webgl/shaders/Shader'), /** diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js index 4e82baa..13892a6 100644 --- a/src/core/renderers/webgl/WebGLRenderer.js +++ b/src/core/renderers/webgl/WebGLRenderer.js @@ -1,5 +1,4 @@ -var WebGLFastSpriteBatch = require('./utils/WebGLFastSpriteBatch'), - WebGLShaderManager = require('./managers/WebGLShaderManager'), +var WebGLShaderManager = require('./managers/WebGLShaderManager'), WebGLMaskManager = require('./managers/WebGLMaskManager'), WebGLFilterManager = require('./managers/WebGLFilterManager'), WebGLBlendModeManager = require('./managers/WebGLBlendModeManager'), @@ -184,12 +183,6 @@ this.shaderManager = new WebGLShaderManager(this); /** - * Manages the rendering of sprites - * @member {WebGLFastSpriteBatch} - */ - this.fastSpriteBatch = new WebGLFastSpriteBatch(this); - - /** * Manages the masks using the stencil buffer * @member {WebGLMaskManager} */ diff --git a/src/core/index.js b/src/core/index.js index 1d0a398..4fc777d 100644 --- a/src/core/index.js +++ b/src/core/index.js @@ -24,6 +24,7 @@ Sprite: require('./sprites/Sprite'), SpriteBatch: require('./sprites/SpriteBatch'), SpriteRenderer: require('./sprites/webgl/SpriteRenderer'), + SpriteBatchRenderer: require('./sprites/webgl/SpriteBatchRenderer'), // primitives Graphics: require('./graphics/Graphics'), @@ -43,6 +44,7 @@ // renderers - webgl WebGLRenderer: require('./renderers/webgl/WebGLRenderer'), + WebGLShaderManager: require('./renderers/webgl/managers/WebGLShaderManager'), Shader: require('./renderers/webgl/shaders/Shader'), /** diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js index 4e82baa..13892a6 100644 --- a/src/core/renderers/webgl/WebGLRenderer.js +++ b/src/core/renderers/webgl/WebGLRenderer.js @@ -1,5 +1,4 @@ -var WebGLFastSpriteBatch = require('./utils/WebGLFastSpriteBatch'), - WebGLShaderManager = require('./managers/WebGLShaderManager'), +var WebGLShaderManager = require('./managers/WebGLShaderManager'), WebGLMaskManager = require('./managers/WebGLMaskManager'), WebGLFilterManager = require('./managers/WebGLFilterManager'), WebGLBlendModeManager = require('./managers/WebGLBlendModeManager'), @@ -184,12 +183,6 @@ this.shaderManager = new WebGLShaderManager(this); /** - * Manages the rendering of sprites - * @member {WebGLFastSpriteBatch} - */ - this.fastSpriteBatch = new WebGLFastSpriteBatch(this); - - /** * Manages the masks using the stencil buffer * @member {WebGLMaskManager} */ diff --git a/src/core/renderers/webgl/shaders/FastShader.js b/src/core/renderers/webgl/shaders/FastShader.js deleted file mode 100644 index c80d040..0000000 --- a/src/core/renderers/webgl/shaders/FastShader.js +++ /dev/null @@ -1,75 +0,0 @@ -var Shader = require('./Shader'), - WebGLShaderManager = require('../managers/WebGLShaderManager'); - -/** - * @class - * @extends Shader - * @namespace PIXI - * @param shaderManager {WebGLShaderManager} The webgl shader manager this shader works for. - */ -function FastShader(shaderManager) -{ - Shader.call(this, - shaderManager, - // vertex shader - [ - 'attribute vec2 aVertexPosition;', - 'attribute vec2 aTextureCoord;', - 'attribute float aColor;', - - 'attribute vec2 aPositionCoord;', - 'attribute vec2 aScale;', - 'attribute float aRotation;', - - 'uniform vec2 projectionVector;', - 'uniform vec2 offsetVector;', - 'uniform mat3 uMatrix;', - - 'varying vec2 vTextureCoord;', - 'varying float vColor;', - - 'const vec2 center = vec2(-1.0, 1.0);', - - 'void main(void){', - ' vec2 v;', - ' vec2 sv = aVertexPosition * aScale;', - ' v.x = (sv.x) * cos(aRotation) - (sv.y) * sin(aRotation);', - ' v.y = (sv.x) * sin(aRotation) + (sv.y) * cos(aRotation);', - ' v = ( uMatrix * vec3(v + aPositionCoord , 1.0) ).xy ;', - ' gl_Position = vec4( ( v / projectionVector) + center , 0.0, 1.0);', - ' vTextureCoord = aTextureCoord;', - // ' vec3 color = mod(vec3(aColor.y/65536.0, aColor.y/256.0, aColor.y), 256.0) / 256.0;', - ' vColor = aColor;', - '}' - ].join('\n'), - // fragment shader, use default - [ - 'precision lowp float;', - - 'varying vec2 vTextureCoord;', - 'varying float vColor;', - - 'uniform sampler2D uSampler;', - - 'void main(void){', - ' gl_FragColor = texture2D(uSampler, vTextureCoord) * vColor ;', - '}' - ].join('\n'), - // custom uniforms - { - uMatrix: { type: 'mat3', value: new Float32Array(9) } - }, - // custom attributes - { - aPositionCoord: 0, - aRotation: 0, - aScale: 0 - } - ); -} - -FastShader.prototype = Object.create(Shader.prototype); -FastShader.prototype.constructor = FastShader; -module.exports = FastShader; - -WebGLShaderManager.registerPlugin('fastShader', FastShader); diff --git a/src/core/index.js b/src/core/index.js index 1d0a398..4fc777d 100644 --- a/src/core/index.js +++ b/src/core/index.js @@ -24,6 +24,7 @@ Sprite: require('./sprites/Sprite'), SpriteBatch: require('./sprites/SpriteBatch'), SpriteRenderer: require('./sprites/webgl/SpriteRenderer'), + SpriteBatchRenderer: require('./sprites/webgl/SpriteBatchRenderer'), // primitives Graphics: require('./graphics/Graphics'), @@ -43,6 +44,7 @@ // renderers - webgl WebGLRenderer: require('./renderers/webgl/WebGLRenderer'), + WebGLShaderManager: require('./renderers/webgl/managers/WebGLShaderManager'), Shader: require('./renderers/webgl/shaders/Shader'), /** diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js index 4e82baa..13892a6 100644 --- a/src/core/renderers/webgl/WebGLRenderer.js +++ b/src/core/renderers/webgl/WebGLRenderer.js @@ -1,5 +1,4 @@ -var WebGLFastSpriteBatch = require('./utils/WebGLFastSpriteBatch'), - WebGLShaderManager = require('./managers/WebGLShaderManager'), +var WebGLShaderManager = require('./managers/WebGLShaderManager'), WebGLMaskManager = require('./managers/WebGLMaskManager'), WebGLFilterManager = require('./managers/WebGLFilterManager'), WebGLBlendModeManager = require('./managers/WebGLBlendModeManager'), @@ -184,12 +183,6 @@ this.shaderManager = new WebGLShaderManager(this); /** - * Manages the rendering of sprites - * @member {WebGLFastSpriteBatch} - */ - this.fastSpriteBatch = new WebGLFastSpriteBatch(this); - - /** * Manages the masks using the stencil buffer * @member {WebGLMaskManager} */ diff --git a/src/core/renderers/webgl/shaders/FastShader.js b/src/core/renderers/webgl/shaders/FastShader.js deleted file mode 100644 index c80d040..0000000 --- a/src/core/renderers/webgl/shaders/FastShader.js +++ /dev/null @@ -1,75 +0,0 @@ -var Shader = require('./Shader'), - WebGLShaderManager = require('../managers/WebGLShaderManager'); - -/** - * @class - * @extends Shader - * @namespace PIXI - * @param shaderManager {WebGLShaderManager} The webgl shader manager this shader works for. - */ -function FastShader(shaderManager) -{ - Shader.call(this, - shaderManager, - // vertex shader - [ - 'attribute vec2 aVertexPosition;', - 'attribute vec2 aTextureCoord;', - 'attribute float aColor;', - - 'attribute vec2 aPositionCoord;', - 'attribute vec2 aScale;', - 'attribute float aRotation;', - - 'uniform vec2 projectionVector;', - 'uniform vec2 offsetVector;', - 'uniform mat3 uMatrix;', - - 'varying vec2 vTextureCoord;', - 'varying float vColor;', - - 'const vec2 center = vec2(-1.0, 1.0);', - - 'void main(void){', - ' vec2 v;', - ' vec2 sv = aVertexPosition * aScale;', - ' v.x = (sv.x) * cos(aRotation) - (sv.y) * sin(aRotation);', - ' v.y = (sv.x) * sin(aRotation) + (sv.y) * cos(aRotation);', - ' v = ( uMatrix * vec3(v + aPositionCoord , 1.0) ).xy ;', - ' gl_Position = vec4( ( v / projectionVector) + center , 0.0, 1.0);', - ' vTextureCoord = aTextureCoord;', - // ' vec3 color = mod(vec3(aColor.y/65536.0, aColor.y/256.0, aColor.y), 256.0) / 256.0;', - ' vColor = aColor;', - '}' - ].join('\n'), - // fragment shader, use default - [ - 'precision lowp float;', - - 'varying vec2 vTextureCoord;', - 'varying float vColor;', - - 'uniform sampler2D uSampler;', - - 'void main(void){', - ' gl_FragColor = texture2D(uSampler, vTextureCoord) * vColor ;', - '}' - ].join('\n'), - // custom uniforms - { - uMatrix: { type: 'mat3', value: new Float32Array(9) } - }, - // custom attributes - { - aPositionCoord: 0, - aRotation: 0, - aScale: 0 - } - ); -} - -FastShader.prototype = Object.create(Shader.prototype); -FastShader.prototype.constructor = FastShader; -module.exports = FastShader; - -WebGLShaderManager.registerPlugin('fastShader', FastShader); diff --git a/src/core/renderers/webgl/shaders/Shader.js b/src/core/renderers/webgl/shaders/Shader.js index c60c5f9..84f321f 100644 --- a/src/core/renderers/webgl/shaders/Shader.js +++ b/src/core/renderers/webgl/shaders/Shader.js @@ -47,7 +47,9 @@ } this.attributes = { - aVertexPosition: 0 + aVertexPosition: 0, + aTextureCoord: 0, + aColor: 0 }; for (var a in customAttributes) @@ -67,7 +69,7 @@ 'attribute vec4 aColor;', 'uniform mat3 projectionMatrix;', - 'uniform vec2 projectionVector;', + // 'uniform vec2 projectionVector;', 'uniform vec2 offsetVector;', 'varying vec2 vTextureCoord;', diff --git a/src/core/index.js b/src/core/index.js index 1d0a398..4fc777d 100644 --- a/src/core/index.js +++ b/src/core/index.js @@ -24,6 +24,7 @@ Sprite: require('./sprites/Sprite'), SpriteBatch: require('./sprites/SpriteBatch'), SpriteRenderer: require('./sprites/webgl/SpriteRenderer'), + SpriteBatchRenderer: require('./sprites/webgl/SpriteBatchRenderer'), // primitives Graphics: require('./graphics/Graphics'), @@ -43,6 +44,7 @@ // renderers - webgl WebGLRenderer: require('./renderers/webgl/WebGLRenderer'), + WebGLShaderManager: require('./renderers/webgl/managers/WebGLShaderManager'), Shader: require('./renderers/webgl/shaders/Shader'), /** diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js index 4e82baa..13892a6 100644 --- a/src/core/renderers/webgl/WebGLRenderer.js +++ b/src/core/renderers/webgl/WebGLRenderer.js @@ -1,5 +1,4 @@ -var WebGLFastSpriteBatch = require('./utils/WebGLFastSpriteBatch'), - WebGLShaderManager = require('./managers/WebGLShaderManager'), +var WebGLShaderManager = require('./managers/WebGLShaderManager'), WebGLMaskManager = require('./managers/WebGLMaskManager'), WebGLFilterManager = require('./managers/WebGLFilterManager'), WebGLBlendModeManager = require('./managers/WebGLBlendModeManager'), @@ -184,12 +183,6 @@ this.shaderManager = new WebGLShaderManager(this); /** - * Manages the rendering of sprites - * @member {WebGLFastSpriteBatch} - */ - this.fastSpriteBatch = new WebGLFastSpriteBatch(this); - - /** * Manages the masks using the stencil buffer * @member {WebGLMaskManager} */ diff --git a/src/core/renderers/webgl/shaders/FastShader.js b/src/core/renderers/webgl/shaders/FastShader.js deleted file mode 100644 index c80d040..0000000 --- a/src/core/renderers/webgl/shaders/FastShader.js +++ /dev/null @@ -1,75 +0,0 @@ -var Shader = require('./Shader'), - WebGLShaderManager = require('../managers/WebGLShaderManager'); - -/** - * @class - * @extends Shader - * @namespace PIXI - * @param shaderManager {WebGLShaderManager} The webgl shader manager this shader works for. - */ -function FastShader(shaderManager) -{ - Shader.call(this, - shaderManager, - // vertex shader - [ - 'attribute vec2 aVertexPosition;', - 'attribute vec2 aTextureCoord;', - 'attribute float aColor;', - - 'attribute vec2 aPositionCoord;', - 'attribute vec2 aScale;', - 'attribute float aRotation;', - - 'uniform vec2 projectionVector;', - 'uniform vec2 offsetVector;', - 'uniform mat3 uMatrix;', - - 'varying vec2 vTextureCoord;', - 'varying float vColor;', - - 'const vec2 center = vec2(-1.0, 1.0);', - - 'void main(void){', - ' vec2 v;', - ' vec2 sv = aVertexPosition * aScale;', - ' v.x = (sv.x) * cos(aRotation) - (sv.y) * sin(aRotation);', - ' v.y = (sv.x) * sin(aRotation) + (sv.y) * cos(aRotation);', - ' v = ( uMatrix * vec3(v + aPositionCoord , 1.0) ).xy ;', - ' gl_Position = vec4( ( v / projectionVector) + center , 0.0, 1.0);', - ' vTextureCoord = aTextureCoord;', - // ' vec3 color = mod(vec3(aColor.y/65536.0, aColor.y/256.0, aColor.y), 256.0) / 256.0;', - ' vColor = aColor;', - '}' - ].join('\n'), - // fragment shader, use default - [ - 'precision lowp float;', - - 'varying vec2 vTextureCoord;', - 'varying float vColor;', - - 'uniform sampler2D uSampler;', - - 'void main(void){', - ' gl_FragColor = texture2D(uSampler, vTextureCoord) * vColor ;', - '}' - ].join('\n'), - // custom uniforms - { - uMatrix: { type: 'mat3', value: new Float32Array(9) } - }, - // custom attributes - { - aPositionCoord: 0, - aRotation: 0, - aScale: 0 - } - ); -} - -FastShader.prototype = Object.create(Shader.prototype); -FastShader.prototype.constructor = FastShader; -module.exports = FastShader; - -WebGLShaderManager.registerPlugin('fastShader', FastShader); diff --git a/src/core/renderers/webgl/shaders/Shader.js b/src/core/renderers/webgl/shaders/Shader.js index c60c5f9..84f321f 100644 --- a/src/core/renderers/webgl/shaders/Shader.js +++ b/src/core/renderers/webgl/shaders/Shader.js @@ -47,7 +47,9 @@ } this.attributes = { - aVertexPosition: 0 + aVertexPosition: 0, + aTextureCoord: 0, + aColor: 0 }; for (var a in customAttributes) @@ -67,7 +69,7 @@ 'attribute vec4 aColor;', 'uniform mat3 projectionMatrix;', - 'uniform vec2 projectionVector;', + // 'uniform vec2 projectionVector;', 'uniform vec2 offsetVector;', 'varying vec2 vTextureCoord;', diff --git a/src/core/renderers/webgl/utils/ObjectRenderer.js b/src/core/renderers/webgl/utils/ObjectRenderer.js index 3b5f432..a07a9b7 100644 --- a/src/core/renderers/webgl/utils/ObjectRenderer.js +++ b/src/core/renderers/webgl/utils/ObjectRenderer.js @@ -25,7 +25,7 @@ ObjectRenderer.prototype.stop = function () { - // flush! + this.flush(); }; ObjectRenderer.prototype.flush = function () diff --git a/src/core/index.js b/src/core/index.js index 1d0a398..4fc777d 100644 --- a/src/core/index.js +++ b/src/core/index.js @@ -24,6 +24,7 @@ Sprite: require('./sprites/Sprite'), SpriteBatch: require('./sprites/SpriteBatch'), SpriteRenderer: require('./sprites/webgl/SpriteRenderer'), + SpriteBatchRenderer: require('./sprites/webgl/SpriteBatchRenderer'), // primitives Graphics: require('./graphics/Graphics'), @@ -43,6 +44,7 @@ // renderers - webgl WebGLRenderer: require('./renderers/webgl/WebGLRenderer'), + WebGLShaderManager: require('./renderers/webgl/managers/WebGLShaderManager'), Shader: require('./renderers/webgl/shaders/Shader'), /** diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js index 4e82baa..13892a6 100644 --- a/src/core/renderers/webgl/WebGLRenderer.js +++ b/src/core/renderers/webgl/WebGLRenderer.js @@ -1,5 +1,4 @@ -var WebGLFastSpriteBatch = require('./utils/WebGLFastSpriteBatch'), - WebGLShaderManager = require('./managers/WebGLShaderManager'), +var WebGLShaderManager = require('./managers/WebGLShaderManager'), WebGLMaskManager = require('./managers/WebGLMaskManager'), WebGLFilterManager = require('./managers/WebGLFilterManager'), WebGLBlendModeManager = require('./managers/WebGLBlendModeManager'), @@ -184,12 +183,6 @@ this.shaderManager = new WebGLShaderManager(this); /** - * Manages the rendering of sprites - * @member {WebGLFastSpriteBatch} - */ - this.fastSpriteBatch = new WebGLFastSpriteBatch(this); - - /** * Manages the masks using the stencil buffer * @member {WebGLMaskManager} */ diff --git a/src/core/renderers/webgl/shaders/FastShader.js b/src/core/renderers/webgl/shaders/FastShader.js deleted file mode 100644 index c80d040..0000000 --- a/src/core/renderers/webgl/shaders/FastShader.js +++ /dev/null @@ -1,75 +0,0 @@ -var Shader = require('./Shader'), - WebGLShaderManager = require('../managers/WebGLShaderManager'); - -/** - * @class - * @extends Shader - * @namespace PIXI - * @param shaderManager {WebGLShaderManager} The webgl shader manager this shader works for. - */ -function FastShader(shaderManager) -{ - Shader.call(this, - shaderManager, - // vertex shader - [ - 'attribute vec2 aVertexPosition;', - 'attribute vec2 aTextureCoord;', - 'attribute float aColor;', - - 'attribute vec2 aPositionCoord;', - 'attribute vec2 aScale;', - 'attribute float aRotation;', - - 'uniform vec2 projectionVector;', - 'uniform vec2 offsetVector;', - 'uniform mat3 uMatrix;', - - 'varying vec2 vTextureCoord;', - 'varying float vColor;', - - 'const vec2 center = vec2(-1.0, 1.0);', - - 'void main(void){', - ' vec2 v;', - ' vec2 sv = aVertexPosition * aScale;', - ' v.x = (sv.x) * cos(aRotation) - (sv.y) * sin(aRotation);', - ' v.y = (sv.x) * sin(aRotation) + (sv.y) * cos(aRotation);', - ' v = ( uMatrix * vec3(v + aPositionCoord , 1.0) ).xy ;', - ' gl_Position = vec4( ( v / projectionVector) + center , 0.0, 1.0);', - ' vTextureCoord = aTextureCoord;', - // ' vec3 color = mod(vec3(aColor.y/65536.0, aColor.y/256.0, aColor.y), 256.0) / 256.0;', - ' vColor = aColor;', - '}' - ].join('\n'), - // fragment shader, use default - [ - 'precision lowp float;', - - 'varying vec2 vTextureCoord;', - 'varying float vColor;', - - 'uniform sampler2D uSampler;', - - 'void main(void){', - ' gl_FragColor = texture2D(uSampler, vTextureCoord) * vColor ;', - '}' - ].join('\n'), - // custom uniforms - { - uMatrix: { type: 'mat3', value: new Float32Array(9) } - }, - // custom attributes - { - aPositionCoord: 0, - aRotation: 0, - aScale: 0 - } - ); -} - -FastShader.prototype = Object.create(Shader.prototype); -FastShader.prototype.constructor = FastShader; -module.exports = FastShader; - -WebGLShaderManager.registerPlugin('fastShader', FastShader); diff --git a/src/core/renderers/webgl/shaders/Shader.js b/src/core/renderers/webgl/shaders/Shader.js index c60c5f9..84f321f 100644 --- a/src/core/renderers/webgl/shaders/Shader.js +++ b/src/core/renderers/webgl/shaders/Shader.js @@ -47,7 +47,9 @@ } this.attributes = { - aVertexPosition: 0 + aVertexPosition: 0, + aTextureCoord: 0, + aColor: 0 }; for (var a in customAttributes) @@ -67,7 +69,7 @@ 'attribute vec4 aColor;', 'uniform mat3 projectionMatrix;', - 'uniform vec2 projectionVector;', + // 'uniform vec2 projectionVector;', 'uniform vec2 offsetVector;', 'varying vec2 vTextureCoord;', diff --git a/src/core/renderers/webgl/utils/ObjectRenderer.js b/src/core/renderers/webgl/utils/ObjectRenderer.js index 3b5f432..a07a9b7 100644 --- a/src/core/renderers/webgl/utils/ObjectRenderer.js +++ b/src/core/renderers/webgl/utils/ObjectRenderer.js @@ -25,7 +25,7 @@ ObjectRenderer.prototype.stop = function () { - // flush! + this.flush(); }; ObjectRenderer.prototype.flush = function () diff --git a/src/core/renderers/webgl/utils/WebGLFastSpriteBatch.js b/src/core/renderers/webgl/utils/WebGLFastSpriteBatch.js deleted file mode 100644 index 3f37b7d..0000000 --- a/src/core/renderers/webgl/utils/WebGLFastSpriteBatch.js +++ /dev/null @@ -1,466 +0,0 @@ -/** - * @author Mat Groves - * - * Big thanks to the very clever Matt DesLauriers 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 - */ - -/** - * @class - * @private - * @namespace PIXI - * @param renderer {WebGLRenderer} The renderer this sprite batch works for. - */ -function WebGLFastSpriteBatch(renderer) -{ - /** - * The renderer instance this sprite batch operates on. - * - * @member {WebGLRenderer} - */ - this.renderer = renderer; - - /** - * - * - * @member {number} - */ - this.vertSize = 10; - - /** - * - * - * @member {number} - */ - this.vertByteSize = this.vertSize * 4; - - /** - * - * - * @member {number} - */ - this.maxSize = 6000;//Math.pow(2, 16) / this.vertSize; - - /** - * - * - * @member {number} - */ - this.size = this.maxSize; - - //the total number of floats in our batch - var numVerts = this.size * this.vertByteSize; - - //the total number of indices in our batch - var numIndices = this.maxSize * 6; - - /** - * Vertex data - * - * @member {Float32Array} - */ - this.vertices = new Float32Array(numVerts); - - /** - * Index data - * - * @member {Uint16Array} - */ - this.indices = new Uint16Array(numIndices); - - /** - * - * - * @member {object} - */ - this.vertexBuffer = null; - - /** - * - * - * @member {object} - */ - this.indexBuffer = null; - - /** - * - * - * @member {number} - */ - 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; - } - - /** - * - * - * @member {boolean} - */ - this.drawing = false; - - /** - * - * - * @member {number} - */ - this.currentBatchSize = 0; - - /** - * - * - * @member {BaseTexture} - */ - this.currentBaseTexture = null; - - /** - * - * - * @member {number} - */ - this.currentBlendMode = 0; - - /** - * - * - * @member {object} - */ - this.shader = null; - - /** - * - * - * @member {Matrix} - */ - this.matrix = null; - - // listen for context and update necessary buffers - var self = this; - this.renderer.on('context', function () - { - self.setupContext(); - }); -} - -WebGLFastSpriteBatch.prototype.constructor = WebGLFastSpriteBatch; -module.exports = WebGLFastSpriteBatch; - -/** - * Sets the WebGL Context. - * - * @param gl {WebGLContext} the current WebGL drawing context - */ -WebGLFastSpriteBatch.prototype.setupContext = function () -{ - var gl = this.renderer.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); -}; - -/** - * @param spriteBatch {SpriteBatch} The SpriteBatch container to prepare for. - */ -WebGLFastSpriteBatch.prototype.begin = function (spriteBatch) -{ - this.shader = this.renderer.shaderManager.plugins.fastShader; - - this.matrix = spriteBatch.worldTransform.toArray(true); - - this.start(); -}; - -/** - */ -WebGLFastSpriteBatch.prototype.end = function () -{ - this.flush(); -}; - -/** - * @param spriteBatch {SpriteBatch} The SpriteBatch container to render. - */ -WebGLFastSpriteBatch.prototype.render = function (spriteBatch) -{ - var children = spriteBatch.children; - var sprite = children[0]; - - // if the uvs have not updated then no point rendering just yet! - - // check texture. - if (!sprite.texture._uvs) - { - return; - } - - this.currentBaseTexture = sprite.texture.baseTexture; - - // check blend mode - if (sprite.blendMode !== this.renderer.blendModeManager.currentBlendMode) - { - this.flush(); - this.renderer.blendModeManager.setBlendMode(sprite.blendMode); - } - - for (var i=0,j= children.length; i= this.size) - { - this.flush(); - } -}; - -/** - * - */ -WebGLFastSpriteBatch.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.renderer.gl; - - // bind the current texture - if (!this.currentBaseTexture._glTextures[gl.id]) - { - this.renderer.updateTexture(this.currentBaseTexture, gl); - } - //TODO-SHOUD THIS BE ELSE??!?!?! - else - { - gl.bindTexture(gl.TEXTURE_2D, this.currentBaseTexture._glTextures[gl.id]); - } - - // upload the verts to the buffer - - if (this.currentBatchSize > ( this.size * 0.5 ) ) - { - gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.vertices); - } - else - { - var view = this.vertices.subarray(0, this.currentBatchSize * this.vertByteSize); - - 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.renderer.drawCount++; -}; - - -/** - * Ends the batch and flushes - * - */ -WebGLFastSpriteBatch.prototype.stop = function () -{ - this.flush(); -}; - -/** - * - */ -WebGLFastSpriteBatch.prototype.start = function () -{ - var gl = this.renderer.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.renderer.projection; - gl.uniform2f(this.shader.uniforms.projectionVector._location, projection.x, projection.y); - - // set the matrix - gl.uniformMatrix3fv(this.shader.uniforms.uMatrix._location, false, this.matrix); - - // set the pointers - var stride = this.vertByteSize; - - gl.vertexAttribPointer(this.shader.attributes.aVertexPosition, 2, gl.FLOAT, false, stride, 0); - gl.vertexAttribPointer(this.shader.attributes.aPositionCoord, 2, gl.FLOAT, false, stride, 2 * 4); - gl.vertexAttribPointer(this.shader.attributes.aScale, 2, gl.FLOAT, false, stride, 4 * 4); - gl.vertexAttribPointer(this.shader.attributes.aRotation, 1, gl.FLOAT, false, stride, 6 * 4); - gl.vertexAttribPointer(this.shader.attributes.aTextureCoord, 2, gl.FLOAT, false, stride, 7 * 4); - gl.vertexAttribPointer(this.shader.attributes.aColor, 1, gl.FLOAT, false, stride, 9 * 4); -}; diff --git a/src/core/index.js b/src/core/index.js index 1d0a398..4fc777d 100644 --- a/src/core/index.js +++ b/src/core/index.js @@ -24,6 +24,7 @@ Sprite: require('./sprites/Sprite'), SpriteBatch: require('./sprites/SpriteBatch'), SpriteRenderer: require('./sprites/webgl/SpriteRenderer'), + SpriteBatchRenderer: require('./sprites/webgl/SpriteBatchRenderer'), // primitives Graphics: require('./graphics/Graphics'), @@ -43,6 +44,7 @@ // renderers - webgl WebGLRenderer: require('./renderers/webgl/WebGLRenderer'), + WebGLShaderManager: require('./renderers/webgl/managers/WebGLShaderManager'), Shader: require('./renderers/webgl/shaders/Shader'), /** diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js index 4e82baa..13892a6 100644 --- a/src/core/renderers/webgl/WebGLRenderer.js +++ b/src/core/renderers/webgl/WebGLRenderer.js @@ -1,5 +1,4 @@ -var WebGLFastSpriteBatch = require('./utils/WebGLFastSpriteBatch'), - WebGLShaderManager = require('./managers/WebGLShaderManager'), +var WebGLShaderManager = require('./managers/WebGLShaderManager'), WebGLMaskManager = require('./managers/WebGLMaskManager'), WebGLFilterManager = require('./managers/WebGLFilterManager'), WebGLBlendModeManager = require('./managers/WebGLBlendModeManager'), @@ -184,12 +183,6 @@ this.shaderManager = new WebGLShaderManager(this); /** - * Manages the rendering of sprites - * @member {WebGLFastSpriteBatch} - */ - this.fastSpriteBatch = new WebGLFastSpriteBatch(this); - - /** * Manages the masks using the stencil buffer * @member {WebGLMaskManager} */ diff --git a/src/core/renderers/webgl/shaders/FastShader.js b/src/core/renderers/webgl/shaders/FastShader.js deleted file mode 100644 index c80d040..0000000 --- a/src/core/renderers/webgl/shaders/FastShader.js +++ /dev/null @@ -1,75 +0,0 @@ -var Shader = require('./Shader'), - WebGLShaderManager = require('../managers/WebGLShaderManager'); - -/** - * @class - * @extends Shader - * @namespace PIXI - * @param shaderManager {WebGLShaderManager} The webgl shader manager this shader works for. - */ -function FastShader(shaderManager) -{ - Shader.call(this, - shaderManager, - // vertex shader - [ - 'attribute vec2 aVertexPosition;', - 'attribute vec2 aTextureCoord;', - 'attribute float aColor;', - - 'attribute vec2 aPositionCoord;', - 'attribute vec2 aScale;', - 'attribute float aRotation;', - - 'uniform vec2 projectionVector;', - 'uniform vec2 offsetVector;', - 'uniform mat3 uMatrix;', - - 'varying vec2 vTextureCoord;', - 'varying float vColor;', - - 'const vec2 center = vec2(-1.0, 1.0);', - - 'void main(void){', - ' vec2 v;', - ' vec2 sv = aVertexPosition * aScale;', - ' v.x = (sv.x) * cos(aRotation) - (sv.y) * sin(aRotation);', - ' v.y = (sv.x) * sin(aRotation) + (sv.y) * cos(aRotation);', - ' v = ( uMatrix * vec3(v + aPositionCoord , 1.0) ).xy ;', - ' gl_Position = vec4( ( v / projectionVector) + center , 0.0, 1.0);', - ' vTextureCoord = aTextureCoord;', - // ' vec3 color = mod(vec3(aColor.y/65536.0, aColor.y/256.0, aColor.y), 256.0) / 256.0;', - ' vColor = aColor;', - '}' - ].join('\n'), - // fragment shader, use default - [ - 'precision lowp float;', - - 'varying vec2 vTextureCoord;', - 'varying float vColor;', - - 'uniform sampler2D uSampler;', - - 'void main(void){', - ' gl_FragColor = texture2D(uSampler, vTextureCoord) * vColor ;', - '}' - ].join('\n'), - // custom uniforms - { - uMatrix: { type: 'mat3', value: new Float32Array(9) } - }, - // custom attributes - { - aPositionCoord: 0, - aRotation: 0, - aScale: 0 - } - ); -} - -FastShader.prototype = Object.create(Shader.prototype); -FastShader.prototype.constructor = FastShader; -module.exports = FastShader; - -WebGLShaderManager.registerPlugin('fastShader', FastShader); diff --git a/src/core/renderers/webgl/shaders/Shader.js b/src/core/renderers/webgl/shaders/Shader.js index c60c5f9..84f321f 100644 --- a/src/core/renderers/webgl/shaders/Shader.js +++ b/src/core/renderers/webgl/shaders/Shader.js @@ -47,7 +47,9 @@ } this.attributes = { - aVertexPosition: 0 + aVertexPosition: 0, + aTextureCoord: 0, + aColor: 0 }; for (var a in customAttributes) @@ -67,7 +69,7 @@ 'attribute vec4 aColor;', 'uniform mat3 projectionMatrix;', - 'uniform vec2 projectionVector;', + // 'uniform vec2 projectionVector;', 'uniform vec2 offsetVector;', 'varying vec2 vTextureCoord;', diff --git a/src/core/renderers/webgl/utils/ObjectRenderer.js b/src/core/renderers/webgl/utils/ObjectRenderer.js index 3b5f432..a07a9b7 100644 --- a/src/core/renderers/webgl/utils/ObjectRenderer.js +++ b/src/core/renderers/webgl/utils/ObjectRenderer.js @@ -25,7 +25,7 @@ ObjectRenderer.prototype.stop = function () { - // flush! + this.flush(); }; ObjectRenderer.prototype.flush = function () diff --git a/src/core/renderers/webgl/utils/WebGLFastSpriteBatch.js b/src/core/renderers/webgl/utils/WebGLFastSpriteBatch.js deleted file mode 100644 index 3f37b7d..0000000 --- a/src/core/renderers/webgl/utils/WebGLFastSpriteBatch.js +++ /dev/null @@ -1,466 +0,0 @@ -/** - * @author Mat Groves - * - * Big thanks to the very clever Matt DesLauriers 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 - */ - -/** - * @class - * @private - * @namespace PIXI - * @param renderer {WebGLRenderer} The renderer this sprite batch works for. - */ -function WebGLFastSpriteBatch(renderer) -{ - /** - * The renderer instance this sprite batch operates on. - * - * @member {WebGLRenderer} - */ - this.renderer = renderer; - - /** - * - * - * @member {number} - */ - this.vertSize = 10; - - /** - * - * - * @member {number} - */ - this.vertByteSize = this.vertSize * 4; - - /** - * - * - * @member {number} - */ - this.maxSize = 6000;//Math.pow(2, 16) / this.vertSize; - - /** - * - * - * @member {number} - */ - this.size = this.maxSize; - - //the total number of floats in our batch - var numVerts = this.size * this.vertByteSize; - - //the total number of indices in our batch - var numIndices = this.maxSize * 6; - - /** - * Vertex data - * - * @member {Float32Array} - */ - this.vertices = new Float32Array(numVerts); - - /** - * Index data - * - * @member {Uint16Array} - */ - this.indices = new Uint16Array(numIndices); - - /** - * - * - * @member {object} - */ - this.vertexBuffer = null; - - /** - * - * - * @member {object} - */ - this.indexBuffer = null; - - /** - * - * - * @member {number} - */ - 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; - } - - /** - * - * - * @member {boolean} - */ - this.drawing = false; - - /** - * - * - * @member {number} - */ - this.currentBatchSize = 0; - - /** - * - * - * @member {BaseTexture} - */ - this.currentBaseTexture = null; - - /** - * - * - * @member {number} - */ - this.currentBlendMode = 0; - - /** - * - * - * @member {object} - */ - this.shader = null; - - /** - * - * - * @member {Matrix} - */ - this.matrix = null; - - // listen for context and update necessary buffers - var self = this; - this.renderer.on('context', function () - { - self.setupContext(); - }); -} - -WebGLFastSpriteBatch.prototype.constructor = WebGLFastSpriteBatch; -module.exports = WebGLFastSpriteBatch; - -/** - * Sets the WebGL Context. - * - * @param gl {WebGLContext} the current WebGL drawing context - */ -WebGLFastSpriteBatch.prototype.setupContext = function () -{ - var gl = this.renderer.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); -}; - -/** - * @param spriteBatch {SpriteBatch} The SpriteBatch container to prepare for. - */ -WebGLFastSpriteBatch.prototype.begin = function (spriteBatch) -{ - this.shader = this.renderer.shaderManager.plugins.fastShader; - - this.matrix = spriteBatch.worldTransform.toArray(true); - - this.start(); -}; - -/** - */ -WebGLFastSpriteBatch.prototype.end = function () -{ - this.flush(); -}; - -/** - * @param spriteBatch {SpriteBatch} The SpriteBatch container to render. - */ -WebGLFastSpriteBatch.prototype.render = function (spriteBatch) -{ - var children = spriteBatch.children; - var sprite = children[0]; - - // if the uvs have not updated then no point rendering just yet! - - // check texture. - if (!sprite.texture._uvs) - { - return; - } - - this.currentBaseTexture = sprite.texture.baseTexture; - - // check blend mode - if (sprite.blendMode !== this.renderer.blendModeManager.currentBlendMode) - { - this.flush(); - this.renderer.blendModeManager.setBlendMode(sprite.blendMode); - } - - for (var i=0,j= children.length; i= this.size) - { - this.flush(); - } -}; - -/** - * - */ -WebGLFastSpriteBatch.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.renderer.gl; - - // bind the current texture - if (!this.currentBaseTexture._glTextures[gl.id]) - { - this.renderer.updateTexture(this.currentBaseTexture, gl); - } - //TODO-SHOUD THIS BE ELSE??!?!?! - else - { - gl.bindTexture(gl.TEXTURE_2D, this.currentBaseTexture._glTextures[gl.id]); - } - - // upload the verts to the buffer - - if (this.currentBatchSize > ( this.size * 0.5 ) ) - { - gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.vertices); - } - else - { - var view = this.vertices.subarray(0, this.currentBatchSize * this.vertByteSize); - - 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.renderer.drawCount++; -}; - - -/** - * Ends the batch and flushes - * - */ -WebGLFastSpriteBatch.prototype.stop = function () -{ - this.flush(); -}; - -/** - * - */ -WebGLFastSpriteBatch.prototype.start = function () -{ - var gl = this.renderer.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.renderer.projection; - gl.uniform2f(this.shader.uniforms.projectionVector._location, projection.x, projection.y); - - // set the matrix - gl.uniformMatrix3fv(this.shader.uniforms.uMatrix._location, false, this.matrix); - - // set the pointers - var stride = this.vertByteSize; - - gl.vertexAttribPointer(this.shader.attributes.aVertexPosition, 2, gl.FLOAT, false, stride, 0); - gl.vertexAttribPointer(this.shader.attributes.aPositionCoord, 2, gl.FLOAT, false, stride, 2 * 4); - gl.vertexAttribPointer(this.shader.attributes.aScale, 2, gl.FLOAT, false, stride, 4 * 4); - gl.vertexAttribPointer(this.shader.attributes.aRotation, 1, gl.FLOAT, false, stride, 6 * 4); - gl.vertexAttribPointer(this.shader.attributes.aTextureCoord, 2, gl.FLOAT, false, stride, 7 * 4); - gl.vertexAttribPointer(this.shader.attributes.aColor, 1, gl.FLOAT, false, stride, 9 * 4); -}; diff --git a/src/core/sprites/SpriteBatch.js b/src/core/sprites/SpriteBatch.js index 4fe33e4..c1e674c 100644 --- a/src/core/sprites/SpriteBatch.js +++ b/src/core/sprites/SpriteBatch.js @@ -59,14 +59,23 @@ return; } - renderer.spriteBatch.stop(); + // renderer.spriteBatch.stop(); - renderer.shaderManager.setShader(renderer.shaderManager.plugins.fastShader); + // renderer.shaderManager.setShader(renderer.shaderManager.plugins.fastShader); - renderer.fastSpriteBatch.begin(this); - renderer.fastSpriteBatch.render(this); + // renderer.fastSpriteBatch.begin(this); + // renderer.fastSpriteBatch.render(this); - renderer.spriteBatch.start(); + // renderer.spriteBatch.start(); + + renderer.currentRenderer.stop(); + + renderer.shaderManager.setShader(renderer.plugins.spriteBatch.shader); + + renderer.plugins.spriteBatch.start(this); + renderer.plugins.spriteBatch.render(this); + + renderer.currentRenderer.start(); }; /** diff --git a/src/core/index.js b/src/core/index.js index 1d0a398..4fc777d 100644 --- a/src/core/index.js +++ b/src/core/index.js @@ -24,6 +24,7 @@ Sprite: require('./sprites/Sprite'), SpriteBatch: require('./sprites/SpriteBatch'), SpriteRenderer: require('./sprites/webgl/SpriteRenderer'), + SpriteBatchRenderer: require('./sprites/webgl/SpriteBatchRenderer'), // primitives Graphics: require('./graphics/Graphics'), @@ -43,6 +44,7 @@ // renderers - webgl WebGLRenderer: require('./renderers/webgl/WebGLRenderer'), + WebGLShaderManager: require('./renderers/webgl/managers/WebGLShaderManager'), Shader: require('./renderers/webgl/shaders/Shader'), /** diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js index 4e82baa..13892a6 100644 --- a/src/core/renderers/webgl/WebGLRenderer.js +++ b/src/core/renderers/webgl/WebGLRenderer.js @@ -1,5 +1,4 @@ -var WebGLFastSpriteBatch = require('./utils/WebGLFastSpriteBatch'), - WebGLShaderManager = require('./managers/WebGLShaderManager'), +var WebGLShaderManager = require('./managers/WebGLShaderManager'), WebGLMaskManager = require('./managers/WebGLMaskManager'), WebGLFilterManager = require('./managers/WebGLFilterManager'), WebGLBlendModeManager = require('./managers/WebGLBlendModeManager'), @@ -184,12 +183,6 @@ this.shaderManager = new WebGLShaderManager(this); /** - * Manages the rendering of sprites - * @member {WebGLFastSpriteBatch} - */ - this.fastSpriteBatch = new WebGLFastSpriteBatch(this); - - /** * Manages the masks using the stencil buffer * @member {WebGLMaskManager} */ diff --git a/src/core/renderers/webgl/shaders/FastShader.js b/src/core/renderers/webgl/shaders/FastShader.js deleted file mode 100644 index c80d040..0000000 --- a/src/core/renderers/webgl/shaders/FastShader.js +++ /dev/null @@ -1,75 +0,0 @@ -var Shader = require('./Shader'), - WebGLShaderManager = require('../managers/WebGLShaderManager'); - -/** - * @class - * @extends Shader - * @namespace PIXI - * @param shaderManager {WebGLShaderManager} The webgl shader manager this shader works for. - */ -function FastShader(shaderManager) -{ - Shader.call(this, - shaderManager, - // vertex shader - [ - 'attribute vec2 aVertexPosition;', - 'attribute vec2 aTextureCoord;', - 'attribute float aColor;', - - 'attribute vec2 aPositionCoord;', - 'attribute vec2 aScale;', - 'attribute float aRotation;', - - 'uniform vec2 projectionVector;', - 'uniform vec2 offsetVector;', - 'uniform mat3 uMatrix;', - - 'varying vec2 vTextureCoord;', - 'varying float vColor;', - - 'const vec2 center = vec2(-1.0, 1.0);', - - 'void main(void){', - ' vec2 v;', - ' vec2 sv = aVertexPosition * aScale;', - ' v.x = (sv.x) * cos(aRotation) - (sv.y) * sin(aRotation);', - ' v.y = (sv.x) * sin(aRotation) + (sv.y) * cos(aRotation);', - ' v = ( uMatrix * vec3(v + aPositionCoord , 1.0) ).xy ;', - ' gl_Position = vec4( ( v / projectionVector) + center , 0.0, 1.0);', - ' vTextureCoord = aTextureCoord;', - // ' vec3 color = mod(vec3(aColor.y/65536.0, aColor.y/256.0, aColor.y), 256.0) / 256.0;', - ' vColor = aColor;', - '}' - ].join('\n'), - // fragment shader, use default - [ - 'precision lowp float;', - - 'varying vec2 vTextureCoord;', - 'varying float vColor;', - - 'uniform sampler2D uSampler;', - - 'void main(void){', - ' gl_FragColor = texture2D(uSampler, vTextureCoord) * vColor ;', - '}' - ].join('\n'), - // custom uniforms - { - uMatrix: { type: 'mat3', value: new Float32Array(9) } - }, - // custom attributes - { - aPositionCoord: 0, - aRotation: 0, - aScale: 0 - } - ); -} - -FastShader.prototype = Object.create(Shader.prototype); -FastShader.prototype.constructor = FastShader; -module.exports = FastShader; - -WebGLShaderManager.registerPlugin('fastShader', FastShader); diff --git a/src/core/renderers/webgl/shaders/Shader.js b/src/core/renderers/webgl/shaders/Shader.js index c60c5f9..84f321f 100644 --- a/src/core/renderers/webgl/shaders/Shader.js +++ b/src/core/renderers/webgl/shaders/Shader.js @@ -47,7 +47,9 @@ } this.attributes = { - aVertexPosition: 0 + aVertexPosition: 0, + aTextureCoord: 0, + aColor: 0 }; for (var a in customAttributes) @@ -67,7 +69,7 @@ 'attribute vec4 aColor;', 'uniform mat3 projectionMatrix;', - 'uniform vec2 projectionVector;', + // 'uniform vec2 projectionVector;', 'uniform vec2 offsetVector;', 'varying vec2 vTextureCoord;', diff --git a/src/core/renderers/webgl/utils/ObjectRenderer.js b/src/core/renderers/webgl/utils/ObjectRenderer.js index 3b5f432..a07a9b7 100644 --- a/src/core/renderers/webgl/utils/ObjectRenderer.js +++ b/src/core/renderers/webgl/utils/ObjectRenderer.js @@ -25,7 +25,7 @@ ObjectRenderer.prototype.stop = function () { - // flush! + this.flush(); }; ObjectRenderer.prototype.flush = function () diff --git a/src/core/renderers/webgl/utils/WebGLFastSpriteBatch.js b/src/core/renderers/webgl/utils/WebGLFastSpriteBatch.js deleted file mode 100644 index 3f37b7d..0000000 --- a/src/core/renderers/webgl/utils/WebGLFastSpriteBatch.js +++ /dev/null @@ -1,466 +0,0 @@ -/** - * @author Mat Groves - * - * Big thanks to the very clever Matt DesLauriers 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 - */ - -/** - * @class - * @private - * @namespace PIXI - * @param renderer {WebGLRenderer} The renderer this sprite batch works for. - */ -function WebGLFastSpriteBatch(renderer) -{ - /** - * The renderer instance this sprite batch operates on. - * - * @member {WebGLRenderer} - */ - this.renderer = renderer; - - /** - * - * - * @member {number} - */ - this.vertSize = 10; - - /** - * - * - * @member {number} - */ - this.vertByteSize = this.vertSize * 4; - - /** - * - * - * @member {number} - */ - this.maxSize = 6000;//Math.pow(2, 16) / this.vertSize; - - /** - * - * - * @member {number} - */ - this.size = this.maxSize; - - //the total number of floats in our batch - var numVerts = this.size * this.vertByteSize; - - //the total number of indices in our batch - var numIndices = this.maxSize * 6; - - /** - * Vertex data - * - * @member {Float32Array} - */ - this.vertices = new Float32Array(numVerts); - - /** - * Index data - * - * @member {Uint16Array} - */ - this.indices = new Uint16Array(numIndices); - - /** - * - * - * @member {object} - */ - this.vertexBuffer = null; - - /** - * - * - * @member {object} - */ - this.indexBuffer = null; - - /** - * - * - * @member {number} - */ - 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; - } - - /** - * - * - * @member {boolean} - */ - this.drawing = false; - - /** - * - * - * @member {number} - */ - this.currentBatchSize = 0; - - /** - * - * - * @member {BaseTexture} - */ - this.currentBaseTexture = null; - - /** - * - * - * @member {number} - */ - this.currentBlendMode = 0; - - /** - * - * - * @member {object} - */ - this.shader = null; - - /** - * - * - * @member {Matrix} - */ - this.matrix = null; - - // listen for context and update necessary buffers - var self = this; - this.renderer.on('context', function () - { - self.setupContext(); - }); -} - -WebGLFastSpriteBatch.prototype.constructor = WebGLFastSpriteBatch; -module.exports = WebGLFastSpriteBatch; - -/** - * Sets the WebGL Context. - * - * @param gl {WebGLContext} the current WebGL drawing context - */ -WebGLFastSpriteBatch.prototype.setupContext = function () -{ - var gl = this.renderer.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); -}; - -/** - * @param spriteBatch {SpriteBatch} The SpriteBatch container to prepare for. - */ -WebGLFastSpriteBatch.prototype.begin = function (spriteBatch) -{ - this.shader = this.renderer.shaderManager.plugins.fastShader; - - this.matrix = spriteBatch.worldTransform.toArray(true); - - this.start(); -}; - -/** - */ -WebGLFastSpriteBatch.prototype.end = function () -{ - this.flush(); -}; - -/** - * @param spriteBatch {SpriteBatch} The SpriteBatch container to render. - */ -WebGLFastSpriteBatch.prototype.render = function (spriteBatch) -{ - var children = spriteBatch.children; - var sprite = children[0]; - - // if the uvs have not updated then no point rendering just yet! - - // check texture. - if (!sprite.texture._uvs) - { - return; - } - - this.currentBaseTexture = sprite.texture.baseTexture; - - // check blend mode - if (sprite.blendMode !== this.renderer.blendModeManager.currentBlendMode) - { - this.flush(); - this.renderer.blendModeManager.setBlendMode(sprite.blendMode); - } - - for (var i=0,j= children.length; i= this.size) - { - this.flush(); - } -}; - -/** - * - */ -WebGLFastSpriteBatch.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.renderer.gl; - - // bind the current texture - if (!this.currentBaseTexture._glTextures[gl.id]) - { - this.renderer.updateTexture(this.currentBaseTexture, gl); - } - //TODO-SHOUD THIS BE ELSE??!?!?! - else - { - gl.bindTexture(gl.TEXTURE_2D, this.currentBaseTexture._glTextures[gl.id]); - } - - // upload the verts to the buffer - - if (this.currentBatchSize > ( this.size * 0.5 ) ) - { - gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.vertices); - } - else - { - var view = this.vertices.subarray(0, this.currentBatchSize * this.vertByteSize); - - 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.renderer.drawCount++; -}; - - -/** - * Ends the batch and flushes - * - */ -WebGLFastSpriteBatch.prototype.stop = function () -{ - this.flush(); -}; - -/** - * - */ -WebGLFastSpriteBatch.prototype.start = function () -{ - var gl = this.renderer.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.renderer.projection; - gl.uniform2f(this.shader.uniforms.projectionVector._location, projection.x, projection.y); - - // set the matrix - gl.uniformMatrix3fv(this.shader.uniforms.uMatrix._location, false, this.matrix); - - // set the pointers - var stride = this.vertByteSize; - - gl.vertexAttribPointer(this.shader.attributes.aVertexPosition, 2, gl.FLOAT, false, stride, 0); - gl.vertexAttribPointer(this.shader.attributes.aPositionCoord, 2, gl.FLOAT, false, stride, 2 * 4); - gl.vertexAttribPointer(this.shader.attributes.aScale, 2, gl.FLOAT, false, stride, 4 * 4); - gl.vertexAttribPointer(this.shader.attributes.aRotation, 1, gl.FLOAT, false, stride, 6 * 4); - gl.vertexAttribPointer(this.shader.attributes.aTextureCoord, 2, gl.FLOAT, false, stride, 7 * 4); - gl.vertexAttribPointer(this.shader.attributes.aColor, 1, gl.FLOAT, false, stride, 9 * 4); -}; diff --git a/src/core/sprites/SpriteBatch.js b/src/core/sprites/SpriteBatch.js index 4fe33e4..c1e674c 100644 --- a/src/core/sprites/SpriteBatch.js +++ b/src/core/sprites/SpriteBatch.js @@ -59,14 +59,23 @@ return; } - renderer.spriteBatch.stop(); + // renderer.spriteBatch.stop(); - renderer.shaderManager.setShader(renderer.shaderManager.plugins.fastShader); + // renderer.shaderManager.setShader(renderer.shaderManager.plugins.fastShader); - renderer.fastSpriteBatch.begin(this); - renderer.fastSpriteBatch.render(this); + // renderer.fastSpriteBatch.begin(this); + // renderer.fastSpriteBatch.render(this); - renderer.spriteBatch.start(); + // renderer.spriteBatch.start(); + + renderer.currentRenderer.stop(); + + renderer.shaderManager.setShader(renderer.plugins.spriteBatch.shader); + + renderer.plugins.spriteBatch.start(this); + renderer.plugins.spriteBatch.render(this); + + renderer.currentRenderer.start(); }; /** diff --git a/src/core/sprites/webgl/SpriteBatchRenderer.js b/src/core/sprites/webgl/SpriteBatchRenderer.js new file mode 100644 index 0000000..82a2318 --- /dev/null +++ b/src/core/sprites/webgl/SpriteBatchRenderer.js @@ -0,0 +1,468 @@ +var ObjectRenderer = require('../../renderers/webgl/utils/ObjectRenderer'), + Shader = require('../../renderers/webgl/shaders/Shader'), + WebGLRenderer = require('../../renderers/webgl/WebGLRenderer'), + SpriteBatchShader = require('./SpriteBatchShader'); + +/** + * @author Mat Groves + * + * Big thanks to the very clever Matt DesLauriers 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 + */ + +/** + * @class + * @private + * @namespace PIXI + * @param renderer {WebGLRenderer} The renderer this sprite batch works for. + */ +function SpriteBatchRenderer(renderer) +{ + ObjectRenderer.call(this, renderer); + + /** + * + * + * @member {number} + */ + this.vertSize = 10; + + /** + * + * + * @member {number} + */ + this.vertByteSize = this.vertSize * 4; + + /** + * + * + * @member {number} + */ + this.maxSize = 6000;//Math.pow(2, 16) / this.vertSize; + + /** + * + * + * @member {number} + */ + this.size = this.maxSize; + + //the total number of floats in our batch + var numVerts = this.size * this.vertByteSize; + + //the total number of indices in our batch + var numIndices = this.maxSize * 6; + + /** + * Vertex data + * + * @member {Float32Array} + */ + this.vertices = new Float32Array(numVerts); + + /** + * Index data + * + * @member {Uint16Array} + */ + this.indices = new Uint16Array(numIndices); + + /** + * + * + * @member {object} + */ + this.vertexBuffer = null; + + /** + * + * + * @member {object} + */ + this.indexBuffer = null; + + /** + * + * + * @member {number} + */ + 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; + } + + /** + * + * + * @member {boolean} + */ + this.drawing = false; + + /** + * + * + * @member {number} + */ + this.currentBatchSize = 0; + + /** + * + * + * @member {BaseTexture} + */ + this.currentBaseTexture = null; + + /** + * + * + * @member {number} + */ + this.currentBlendMode = 0; + + /** + * + * + * @member {object} + */ + this.shader = null; + + this.setupContext(); + + // handle when the renderer's context changes. + this.renderer.on('context', this.setupContext.bind(this)); +} + +SpriteBatchRenderer.prototype = Object.create(ObjectRenderer.prototype); +SpriteBatchRenderer.prototype.constructor = SpriteBatchRenderer; +module.exports = SpriteBatchRenderer; + +WebGLRenderer.registerPlugin('spriteBatch', SpriteBatchRenderer); + +/** + * Sets the WebGL Context. + * + * @param gl {WebGLContext} the current WebGL drawing context + */ +SpriteBatchRenderer.prototype.setupContext = function () +{ + var gl = this.renderer.gl; + + // create a couple of buffers + this.vertexBuffer = gl.createBuffer(); + this.indexBuffer = gl.createBuffer(); + + this.shader = new SpriteBatchShader(this.renderer.shaderManager); + + // 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); +}; + +/** + */ +// SpriteBatchRenderer.prototype.stop = function () +// { +// this.flush(); +// }; + +/** + * @param spriteBatch {SpriteBatch} The SpriteBatch container to render. + */ +SpriteBatchRenderer.prototype.render = function (spriteBatch) +{ + var children = spriteBatch.children; + var sprite = children[0]; + + // if the uvs have not updated then no point rendering just yet! + + // check texture. + if (!sprite.texture._uvs) + { + return; + } + + this.currentBaseTexture = sprite.texture.baseTexture; + + // check blend mode + if (sprite.blendMode !== this.renderer.blendModeManager.currentBlendMode) + { + this.flush(); + this.renderer.blendModeManager.setBlendMode(sprite.blendMode); + } + + for (var i=0,j= children.length; i= this.size) + { + this.flush(); + } +}; + +/** + * + */ +SpriteBatchRenderer.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.renderer.gl; + + // bind the current texture + if (!this.currentBaseTexture._glTextures[gl.id]) + { + this.renderer.updateTexture(this.currentBaseTexture, gl); + } + //TODO-SHOUD THIS BE ELSE??!?!?! + else + { + gl.bindTexture(gl.TEXTURE_2D, this.currentBaseTexture._glTextures[gl.id]); + } + + // upload the verts to the buffer + + if (this.currentBatchSize > ( this.size * 0.5 ) ) + { + gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.vertices); + } + else + { + var view = this.vertices.subarray(0, this.currentBatchSize * this.vertByteSize); + + 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.renderer.drawCount++; +}; + +/** + * + */ +SpriteBatchRenderer.prototype.start = function (spriteBatch) +{ + var gl = this.renderer.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.renderer.projection; + // gl.uniform2f(this.shader.uniforms.projectionVector._location, projection.x, projection.y); + gl.uniformMatrix3fv(this.shader.uniforms.projectionMatrix._location, false, this.renderer.currentRenderTarget.projectionMatrix.toArray(true)); + + // set the matrix from the spriteBatch + gl.uniformMatrix3fv(this.shader.uniforms.uMatrix._location, false, spriteBatch.worldTransform.toArray(true)); + + // set the pointers + var stride = this.vertByteSize; + + gl.vertexAttribPointer(this.shader.attributes.aVertexPosition, 2, gl.FLOAT, false, stride, 0); + gl.vertexAttribPointer(this.shader.attributes.aTextureCoord, 2, gl.FLOAT, false, stride, 2 * 4); + gl.vertexAttribPointer(this.shader.attributes.aColor, 1, gl.FLOAT, false, stride, 4 * 4); + + gl.vertexAttribPointer(this.shader.attributes.aPositionCoord, 2, gl.FLOAT, false, stride, 5 * 4); + gl.vertexAttribPointer(this.shader.attributes.aScale, 2, gl.FLOAT, false, stride, 7 * 4); + gl.vertexAttribPointer(this.shader.attributes.aRotation, 1, gl.FLOAT, false, stride, 9 * 4); +}; + +/** + * Destroys the SpriteBatch. + * + */ +SpriteBatchRenderer.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.currentBaseTexture = null; + + this.drawing = false; + + this.shader = null; +}; diff --git a/src/core/index.js b/src/core/index.js index 1d0a398..4fc777d 100644 --- a/src/core/index.js +++ b/src/core/index.js @@ -24,6 +24,7 @@ Sprite: require('./sprites/Sprite'), SpriteBatch: require('./sprites/SpriteBatch'), SpriteRenderer: require('./sprites/webgl/SpriteRenderer'), + SpriteBatchRenderer: require('./sprites/webgl/SpriteBatchRenderer'), // primitives Graphics: require('./graphics/Graphics'), @@ -43,6 +44,7 @@ // renderers - webgl WebGLRenderer: require('./renderers/webgl/WebGLRenderer'), + WebGLShaderManager: require('./renderers/webgl/managers/WebGLShaderManager'), Shader: require('./renderers/webgl/shaders/Shader'), /** diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js index 4e82baa..13892a6 100644 --- a/src/core/renderers/webgl/WebGLRenderer.js +++ b/src/core/renderers/webgl/WebGLRenderer.js @@ -1,5 +1,4 @@ -var WebGLFastSpriteBatch = require('./utils/WebGLFastSpriteBatch'), - WebGLShaderManager = require('./managers/WebGLShaderManager'), +var WebGLShaderManager = require('./managers/WebGLShaderManager'), WebGLMaskManager = require('./managers/WebGLMaskManager'), WebGLFilterManager = require('./managers/WebGLFilterManager'), WebGLBlendModeManager = require('./managers/WebGLBlendModeManager'), @@ -184,12 +183,6 @@ this.shaderManager = new WebGLShaderManager(this); /** - * Manages the rendering of sprites - * @member {WebGLFastSpriteBatch} - */ - this.fastSpriteBatch = new WebGLFastSpriteBatch(this); - - /** * Manages the masks using the stencil buffer * @member {WebGLMaskManager} */ diff --git a/src/core/renderers/webgl/shaders/FastShader.js b/src/core/renderers/webgl/shaders/FastShader.js deleted file mode 100644 index c80d040..0000000 --- a/src/core/renderers/webgl/shaders/FastShader.js +++ /dev/null @@ -1,75 +0,0 @@ -var Shader = require('./Shader'), - WebGLShaderManager = require('../managers/WebGLShaderManager'); - -/** - * @class - * @extends Shader - * @namespace PIXI - * @param shaderManager {WebGLShaderManager} The webgl shader manager this shader works for. - */ -function FastShader(shaderManager) -{ - Shader.call(this, - shaderManager, - // vertex shader - [ - 'attribute vec2 aVertexPosition;', - 'attribute vec2 aTextureCoord;', - 'attribute float aColor;', - - 'attribute vec2 aPositionCoord;', - 'attribute vec2 aScale;', - 'attribute float aRotation;', - - 'uniform vec2 projectionVector;', - 'uniform vec2 offsetVector;', - 'uniform mat3 uMatrix;', - - 'varying vec2 vTextureCoord;', - 'varying float vColor;', - - 'const vec2 center = vec2(-1.0, 1.0);', - - 'void main(void){', - ' vec2 v;', - ' vec2 sv = aVertexPosition * aScale;', - ' v.x = (sv.x) * cos(aRotation) - (sv.y) * sin(aRotation);', - ' v.y = (sv.x) * sin(aRotation) + (sv.y) * cos(aRotation);', - ' v = ( uMatrix * vec3(v + aPositionCoord , 1.0) ).xy ;', - ' gl_Position = vec4( ( v / projectionVector) + center , 0.0, 1.0);', - ' vTextureCoord = aTextureCoord;', - // ' vec3 color = mod(vec3(aColor.y/65536.0, aColor.y/256.0, aColor.y), 256.0) / 256.0;', - ' vColor = aColor;', - '}' - ].join('\n'), - // fragment shader, use default - [ - 'precision lowp float;', - - 'varying vec2 vTextureCoord;', - 'varying float vColor;', - - 'uniform sampler2D uSampler;', - - 'void main(void){', - ' gl_FragColor = texture2D(uSampler, vTextureCoord) * vColor ;', - '}' - ].join('\n'), - // custom uniforms - { - uMatrix: { type: 'mat3', value: new Float32Array(9) } - }, - // custom attributes - { - aPositionCoord: 0, - aRotation: 0, - aScale: 0 - } - ); -} - -FastShader.prototype = Object.create(Shader.prototype); -FastShader.prototype.constructor = FastShader; -module.exports = FastShader; - -WebGLShaderManager.registerPlugin('fastShader', FastShader); diff --git a/src/core/renderers/webgl/shaders/Shader.js b/src/core/renderers/webgl/shaders/Shader.js index c60c5f9..84f321f 100644 --- a/src/core/renderers/webgl/shaders/Shader.js +++ b/src/core/renderers/webgl/shaders/Shader.js @@ -47,7 +47,9 @@ } this.attributes = { - aVertexPosition: 0 + aVertexPosition: 0, + aTextureCoord: 0, + aColor: 0 }; for (var a in customAttributes) @@ -67,7 +69,7 @@ 'attribute vec4 aColor;', 'uniform mat3 projectionMatrix;', - 'uniform vec2 projectionVector;', + // 'uniform vec2 projectionVector;', 'uniform vec2 offsetVector;', 'varying vec2 vTextureCoord;', diff --git a/src/core/renderers/webgl/utils/ObjectRenderer.js b/src/core/renderers/webgl/utils/ObjectRenderer.js index 3b5f432..a07a9b7 100644 --- a/src/core/renderers/webgl/utils/ObjectRenderer.js +++ b/src/core/renderers/webgl/utils/ObjectRenderer.js @@ -25,7 +25,7 @@ ObjectRenderer.prototype.stop = function () { - // flush! + this.flush(); }; ObjectRenderer.prototype.flush = function () diff --git a/src/core/renderers/webgl/utils/WebGLFastSpriteBatch.js b/src/core/renderers/webgl/utils/WebGLFastSpriteBatch.js deleted file mode 100644 index 3f37b7d..0000000 --- a/src/core/renderers/webgl/utils/WebGLFastSpriteBatch.js +++ /dev/null @@ -1,466 +0,0 @@ -/** - * @author Mat Groves - * - * Big thanks to the very clever Matt DesLauriers 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 - */ - -/** - * @class - * @private - * @namespace PIXI - * @param renderer {WebGLRenderer} The renderer this sprite batch works for. - */ -function WebGLFastSpriteBatch(renderer) -{ - /** - * The renderer instance this sprite batch operates on. - * - * @member {WebGLRenderer} - */ - this.renderer = renderer; - - /** - * - * - * @member {number} - */ - this.vertSize = 10; - - /** - * - * - * @member {number} - */ - this.vertByteSize = this.vertSize * 4; - - /** - * - * - * @member {number} - */ - this.maxSize = 6000;//Math.pow(2, 16) / this.vertSize; - - /** - * - * - * @member {number} - */ - this.size = this.maxSize; - - //the total number of floats in our batch - var numVerts = this.size * this.vertByteSize; - - //the total number of indices in our batch - var numIndices = this.maxSize * 6; - - /** - * Vertex data - * - * @member {Float32Array} - */ - this.vertices = new Float32Array(numVerts); - - /** - * Index data - * - * @member {Uint16Array} - */ - this.indices = new Uint16Array(numIndices); - - /** - * - * - * @member {object} - */ - this.vertexBuffer = null; - - /** - * - * - * @member {object} - */ - this.indexBuffer = null; - - /** - * - * - * @member {number} - */ - 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; - } - - /** - * - * - * @member {boolean} - */ - this.drawing = false; - - /** - * - * - * @member {number} - */ - this.currentBatchSize = 0; - - /** - * - * - * @member {BaseTexture} - */ - this.currentBaseTexture = null; - - /** - * - * - * @member {number} - */ - this.currentBlendMode = 0; - - /** - * - * - * @member {object} - */ - this.shader = null; - - /** - * - * - * @member {Matrix} - */ - this.matrix = null; - - // listen for context and update necessary buffers - var self = this; - this.renderer.on('context', function () - { - self.setupContext(); - }); -} - -WebGLFastSpriteBatch.prototype.constructor = WebGLFastSpriteBatch; -module.exports = WebGLFastSpriteBatch; - -/** - * Sets the WebGL Context. - * - * @param gl {WebGLContext} the current WebGL drawing context - */ -WebGLFastSpriteBatch.prototype.setupContext = function () -{ - var gl = this.renderer.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); -}; - -/** - * @param spriteBatch {SpriteBatch} The SpriteBatch container to prepare for. - */ -WebGLFastSpriteBatch.prototype.begin = function (spriteBatch) -{ - this.shader = this.renderer.shaderManager.plugins.fastShader; - - this.matrix = spriteBatch.worldTransform.toArray(true); - - this.start(); -}; - -/** - */ -WebGLFastSpriteBatch.prototype.end = function () -{ - this.flush(); -}; - -/** - * @param spriteBatch {SpriteBatch} The SpriteBatch container to render. - */ -WebGLFastSpriteBatch.prototype.render = function (spriteBatch) -{ - var children = spriteBatch.children; - var sprite = children[0]; - - // if the uvs have not updated then no point rendering just yet! - - // check texture. - if (!sprite.texture._uvs) - { - return; - } - - this.currentBaseTexture = sprite.texture.baseTexture; - - // check blend mode - if (sprite.blendMode !== this.renderer.blendModeManager.currentBlendMode) - { - this.flush(); - this.renderer.blendModeManager.setBlendMode(sprite.blendMode); - } - - for (var i=0,j= children.length; i= this.size) - { - this.flush(); - } -}; - -/** - * - */ -WebGLFastSpriteBatch.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.renderer.gl; - - // bind the current texture - if (!this.currentBaseTexture._glTextures[gl.id]) - { - this.renderer.updateTexture(this.currentBaseTexture, gl); - } - //TODO-SHOUD THIS BE ELSE??!?!?! - else - { - gl.bindTexture(gl.TEXTURE_2D, this.currentBaseTexture._glTextures[gl.id]); - } - - // upload the verts to the buffer - - if (this.currentBatchSize > ( this.size * 0.5 ) ) - { - gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.vertices); - } - else - { - var view = this.vertices.subarray(0, this.currentBatchSize * this.vertByteSize); - - 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.renderer.drawCount++; -}; - - -/** - * Ends the batch and flushes - * - */ -WebGLFastSpriteBatch.prototype.stop = function () -{ - this.flush(); -}; - -/** - * - */ -WebGLFastSpriteBatch.prototype.start = function () -{ - var gl = this.renderer.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.renderer.projection; - gl.uniform2f(this.shader.uniforms.projectionVector._location, projection.x, projection.y); - - // set the matrix - gl.uniformMatrix3fv(this.shader.uniforms.uMatrix._location, false, this.matrix); - - // set the pointers - var stride = this.vertByteSize; - - gl.vertexAttribPointer(this.shader.attributes.aVertexPosition, 2, gl.FLOAT, false, stride, 0); - gl.vertexAttribPointer(this.shader.attributes.aPositionCoord, 2, gl.FLOAT, false, stride, 2 * 4); - gl.vertexAttribPointer(this.shader.attributes.aScale, 2, gl.FLOAT, false, stride, 4 * 4); - gl.vertexAttribPointer(this.shader.attributes.aRotation, 1, gl.FLOAT, false, stride, 6 * 4); - gl.vertexAttribPointer(this.shader.attributes.aTextureCoord, 2, gl.FLOAT, false, stride, 7 * 4); - gl.vertexAttribPointer(this.shader.attributes.aColor, 1, gl.FLOAT, false, stride, 9 * 4); -}; diff --git a/src/core/sprites/SpriteBatch.js b/src/core/sprites/SpriteBatch.js index 4fe33e4..c1e674c 100644 --- a/src/core/sprites/SpriteBatch.js +++ b/src/core/sprites/SpriteBatch.js @@ -59,14 +59,23 @@ return; } - renderer.spriteBatch.stop(); + // renderer.spriteBatch.stop(); - renderer.shaderManager.setShader(renderer.shaderManager.plugins.fastShader); + // renderer.shaderManager.setShader(renderer.shaderManager.plugins.fastShader); - renderer.fastSpriteBatch.begin(this); - renderer.fastSpriteBatch.render(this); + // renderer.fastSpriteBatch.begin(this); + // renderer.fastSpriteBatch.render(this); - renderer.spriteBatch.start(); + // renderer.spriteBatch.start(); + + renderer.currentRenderer.stop(); + + renderer.shaderManager.setShader(renderer.plugins.spriteBatch.shader); + + renderer.plugins.spriteBatch.start(this); + renderer.plugins.spriteBatch.render(this); + + renderer.currentRenderer.start(); }; /** diff --git a/src/core/sprites/webgl/SpriteBatchRenderer.js b/src/core/sprites/webgl/SpriteBatchRenderer.js new file mode 100644 index 0000000..82a2318 --- /dev/null +++ b/src/core/sprites/webgl/SpriteBatchRenderer.js @@ -0,0 +1,468 @@ +var ObjectRenderer = require('../../renderers/webgl/utils/ObjectRenderer'), + Shader = require('../../renderers/webgl/shaders/Shader'), + WebGLRenderer = require('../../renderers/webgl/WebGLRenderer'), + SpriteBatchShader = require('./SpriteBatchShader'); + +/** + * @author Mat Groves + * + * Big thanks to the very clever Matt DesLauriers 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 + */ + +/** + * @class + * @private + * @namespace PIXI + * @param renderer {WebGLRenderer} The renderer this sprite batch works for. + */ +function SpriteBatchRenderer(renderer) +{ + ObjectRenderer.call(this, renderer); + + /** + * + * + * @member {number} + */ + this.vertSize = 10; + + /** + * + * + * @member {number} + */ + this.vertByteSize = this.vertSize * 4; + + /** + * + * + * @member {number} + */ + this.maxSize = 6000;//Math.pow(2, 16) / this.vertSize; + + /** + * + * + * @member {number} + */ + this.size = this.maxSize; + + //the total number of floats in our batch + var numVerts = this.size * this.vertByteSize; + + //the total number of indices in our batch + var numIndices = this.maxSize * 6; + + /** + * Vertex data + * + * @member {Float32Array} + */ + this.vertices = new Float32Array(numVerts); + + /** + * Index data + * + * @member {Uint16Array} + */ + this.indices = new Uint16Array(numIndices); + + /** + * + * + * @member {object} + */ + this.vertexBuffer = null; + + /** + * + * + * @member {object} + */ + this.indexBuffer = null; + + /** + * + * + * @member {number} + */ + 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; + } + + /** + * + * + * @member {boolean} + */ + this.drawing = false; + + /** + * + * + * @member {number} + */ + this.currentBatchSize = 0; + + /** + * + * + * @member {BaseTexture} + */ + this.currentBaseTexture = null; + + /** + * + * + * @member {number} + */ + this.currentBlendMode = 0; + + /** + * + * + * @member {object} + */ + this.shader = null; + + this.setupContext(); + + // handle when the renderer's context changes. + this.renderer.on('context', this.setupContext.bind(this)); +} + +SpriteBatchRenderer.prototype = Object.create(ObjectRenderer.prototype); +SpriteBatchRenderer.prototype.constructor = SpriteBatchRenderer; +module.exports = SpriteBatchRenderer; + +WebGLRenderer.registerPlugin('spriteBatch', SpriteBatchRenderer); + +/** + * Sets the WebGL Context. + * + * @param gl {WebGLContext} the current WebGL drawing context + */ +SpriteBatchRenderer.prototype.setupContext = function () +{ + var gl = this.renderer.gl; + + // create a couple of buffers + this.vertexBuffer = gl.createBuffer(); + this.indexBuffer = gl.createBuffer(); + + this.shader = new SpriteBatchShader(this.renderer.shaderManager); + + // 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); +}; + +/** + */ +// SpriteBatchRenderer.prototype.stop = function () +// { +// this.flush(); +// }; + +/** + * @param spriteBatch {SpriteBatch} The SpriteBatch container to render. + */ +SpriteBatchRenderer.prototype.render = function (spriteBatch) +{ + var children = spriteBatch.children; + var sprite = children[0]; + + // if the uvs have not updated then no point rendering just yet! + + // check texture. + if (!sprite.texture._uvs) + { + return; + } + + this.currentBaseTexture = sprite.texture.baseTexture; + + // check blend mode + if (sprite.blendMode !== this.renderer.blendModeManager.currentBlendMode) + { + this.flush(); + this.renderer.blendModeManager.setBlendMode(sprite.blendMode); + } + + for (var i=0,j= children.length; i= this.size) + { + this.flush(); + } +}; + +/** + * + */ +SpriteBatchRenderer.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.renderer.gl; + + // bind the current texture + if (!this.currentBaseTexture._glTextures[gl.id]) + { + this.renderer.updateTexture(this.currentBaseTexture, gl); + } + //TODO-SHOUD THIS BE ELSE??!?!?! + else + { + gl.bindTexture(gl.TEXTURE_2D, this.currentBaseTexture._glTextures[gl.id]); + } + + // upload the verts to the buffer + + if (this.currentBatchSize > ( this.size * 0.5 ) ) + { + gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.vertices); + } + else + { + var view = this.vertices.subarray(0, this.currentBatchSize * this.vertByteSize); + + 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.renderer.drawCount++; +}; + +/** + * + */ +SpriteBatchRenderer.prototype.start = function (spriteBatch) +{ + var gl = this.renderer.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.renderer.projection; + // gl.uniform2f(this.shader.uniforms.projectionVector._location, projection.x, projection.y); + gl.uniformMatrix3fv(this.shader.uniforms.projectionMatrix._location, false, this.renderer.currentRenderTarget.projectionMatrix.toArray(true)); + + // set the matrix from the spriteBatch + gl.uniformMatrix3fv(this.shader.uniforms.uMatrix._location, false, spriteBatch.worldTransform.toArray(true)); + + // set the pointers + var stride = this.vertByteSize; + + gl.vertexAttribPointer(this.shader.attributes.aVertexPosition, 2, gl.FLOAT, false, stride, 0); + gl.vertexAttribPointer(this.shader.attributes.aTextureCoord, 2, gl.FLOAT, false, stride, 2 * 4); + gl.vertexAttribPointer(this.shader.attributes.aColor, 1, gl.FLOAT, false, stride, 4 * 4); + + gl.vertexAttribPointer(this.shader.attributes.aPositionCoord, 2, gl.FLOAT, false, stride, 5 * 4); + gl.vertexAttribPointer(this.shader.attributes.aScale, 2, gl.FLOAT, false, stride, 7 * 4); + gl.vertexAttribPointer(this.shader.attributes.aRotation, 1, gl.FLOAT, false, stride, 9 * 4); +}; + +/** + * Destroys the SpriteBatch. + * + */ +SpriteBatchRenderer.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.currentBaseTexture = null; + + this.drawing = false; + + this.shader = null; +}; diff --git a/src/core/sprites/webgl/SpriteBatchShader.js b/src/core/sprites/webgl/SpriteBatchShader.js new file mode 100644 index 0000000..1f53252 --- /dev/null +++ b/src/core/sprites/webgl/SpriteBatchShader.js @@ -0,0 +1,78 @@ +var Shader = require('../../renderers/webgl/shaders/Shader'); + +/** + * @class + * @extends Shader + * @namespace PIXI + * @param shaderManager {WebGLShaderManager} The webgl shader manager this shader works for. + */ +function SpriteBatchShader(shaderManager) +{ + Shader.call(this, + shaderManager, + // vertex shader + [ + 'attribute vec2 aVertexPosition;', + 'attribute vec2 aTextureCoord;', + 'attribute float aColor;', + + 'attribute vec2 aPositionCoord;', + 'attribute vec2 aScale;', + 'attribute float aRotation;', + + 'uniform mat3 projectionMatrix;', + // 'uniform vec2 projectionVector;', + // 'uniform vec2 offsetVector;', + 'uniform mat3 uMatrix;', + + 'varying vec2 vTextureCoord;', + 'varying float vColor;', + + // 'const vec2 center = vec2(-1.0, 1.0);', + + 'void main(void){', + ' vec2 v;', + ' vec2 sv = aVertexPosition * aScale;', + ' v.x = (sv.x) * cos(aRotation) - (sv.y) * sin(aRotation);', + ' v.y = (sv.x) * sin(aRotation) + (sv.y) * cos(aRotation);', + ' v = ( uMatrix * vec3(v + aPositionCoord , 1.0) ).xy ;', + + + // ' gl_Position = vec4( ( v / projectionVector) + center , 0.0, 1.0);', + ' gl_Position = vec4((projectionMatrix * vec3(v, 1.0)).xy, 0.0, 1.0);', + + + ' vTextureCoord = aTextureCoord;', + // ' vec3 color = mod(vec3(aColor.y/65536.0, aColor.y/256.0, aColor.y), 256.0) / 256.0;', + ' vColor = aColor;', + '}' + ].join('\n'), + // fragment shader, use default + [ + 'precision lowp float;', + + 'varying vec2 vTextureCoord;', + 'varying float vColor;', + + 'uniform sampler2D uSampler;', + + 'void main(void){', + ' gl_FragColor = texture2D(uSampler, vTextureCoord) * vColor ;', + '}' + ].join('\n'), + // custom uniforms + { + uMatrix: { type: 'mat3', value: new Float32Array(9) } + }, + // custom attributes + { + aPositionCoord: 0, + aScale: 0, + aRotation: 0 + } + ); +} + +SpriteBatchShader.prototype = Object.create(Shader.prototype); +SpriteBatchShader.prototype.constructor = SpriteBatchShader; +module.exports = SpriteBatchShader; diff --git a/src/core/index.js b/src/core/index.js index 1d0a398..4fc777d 100644 --- a/src/core/index.js +++ b/src/core/index.js @@ -24,6 +24,7 @@ Sprite: require('./sprites/Sprite'), SpriteBatch: require('./sprites/SpriteBatch'), SpriteRenderer: require('./sprites/webgl/SpriteRenderer'), + SpriteBatchRenderer: require('./sprites/webgl/SpriteBatchRenderer'), // primitives Graphics: require('./graphics/Graphics'), @@ -43,6 +44,7 @@ // renderers - webgl WebGLRenderer: require('./renderers/webgl/WebGLRenderer'), + WebGLShaderManager: require('./renderers/webgl/managers/WebGLShaderManager'), Shader: require('./renderers/webgl/shaders/Shader'), /** diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js index 4e82baa..13892a6 100644 --- a/src/core/renderers/webgl/WebGLRenderer.js +++ b/src/core/renderers/webgl/WebGLRenderer.js @@ -1,5 +1,4 @@ -var WebGLFastSpriteBatch = require('./utils/WebGLFastSpriteBatch'), - WebGLShaderManager = require('./managers/WebGLShaderManager'), +var WebGLShaderManager = require('./managers/WebGLShaderManager'), WebGLMaskManager = require('./managers/WebGLMaskManager'), WebGLFilterManager = require('./managers/WebGLFilterManager'), WebGLBlendModeManager = require('./managers/WebGLBlendModeManager'), @@ -184,12 +183,6 @@ this.shaderManager = new WebGLShaderManager(this); /** - * Manages the rendering of sprites - * @member {WebGLFastSpriteBatch} - */ - this.fastSpriteBatch = new WebGLFastSpriteBatch(this); - - /** * Manages the masks using the stencil buffer * @member {WebGLMaskManager} */ diff --git a/src/core/renderers/webgl/shaders/FastShader.js b/src/core/renderers/webgl/shaders/FastShader.js deleted file mode 100644 index c80d040..0000000 --- a/src/core/renderers/webgl/shaders/FastShader.js +++ /dev/null @@ -1,75 +0,0 @@ -var Shader = require('./Shader'), - WebGLShaderManager = require('../managers/WebGLShaderManager'); - -/** - * @class - * @extends Shader - * @namespace PIXI - * @param shaderManager {WebGLShaderManager} The webgl shader manager this shader works for. - */ -function FastShader(shaderManager) -{ - Shader.call(this, - shaderManager, - // vertex shader - [ - 'attribute vec2 aVertexPosition;', - 'attribute vec2 aTextureCoord;', - 'attribute float aColor;', - - 'attribute vec2 aPositionCoord;', - 'attribute vec2 aScale;', - 'attribute float aRotation;', - - 'uniform vec2 projectionVector;', - 'uniform vec2 offsetVector;', - 'uniform mat3 uMatrix;', - - 'varying vec2 vTextureCoord;', - 'varying float vColor;', - - 'const vec2 center = vec2(-1.0, 1.0);', - - 'void main(void){', - ' vec2 v;', - ' vec2 sv = aVertexPosition * aScale;', - ' v.x = (sv.x) * cos(aRotation) - (sv.y) * sin(aRotation);', - ' v.y = (sv.x) * sin(aRotation) + (sv.y) * cos(aRotation);', - ' v = ( uMatrix * vec3(v + aPositionCoord , 1.0) ).xy ;', - ' gl_Position = vec4( ( v / projectionVector) + center , 0.0, 1.0);', - ' vTextureCoord = aTextureCoord;', - // ' vec3 color = mod(vec3(aColor.y/65536.0, aColor.y/256.0, aColor.y), 256.0) / 256.0;', - ' vColor = aColor;', - '}' - ].join('\n'), - // fragment shader, use default - [ - 'precision lowp float;', - - 'varying vec2 vTextureCoord;', - 'varying float vColor;', - - 'uniform sampler2D uSampler;', - - 'void main(void){', - ' gl_FragColor = texture2D(uSampler, vTextureCoord) * vColor ;', - '}' - ].join('\n'), - // custom uniforms - { - uMatrix: { type: 'mat3', value: new Float32Array(9) } - }, - // custom attributes - { - aPositionCoord: 0, - aRotation: 0, - aScale: 0 - } - ); -} - -FastShader.prototype = Object.create(Shader.prototype); -FastShader.prototype.constructor = FastShader; -module.exports = FastShader; - -WebGLShaderManager.registerPlugin('fastShader', FastShader); diff --git a/src/core/renderers/webgl/shaders/Shader.js b/src/core/renderers/webgl/shaders/Shader.js index c60c5f9..84f321f 100644 --- a/src/core/renderers/webgl/shaders/Shader.js +++ b/src/core/renderers/webgl/shaders/Shader.js @@ -47,7 +47,9 @@ } this.attributes = { - aVertexPosition: 0 + aVertexPosition: 0, + aTextureCoord: 0, + aColor: 0 }; for (var a in customAttributes) @@ -67,7 +69,7 @@ 'attribute vec4 aColor;', 'uniform mat3 projectionMatrix;', - 'uniform vec2 projectionVector;', + // 'uniform vec2 projectionVector;', 'uniform vec2 offsetVector;', 'varying vec2 vTextureCoord;', diff --git a/src/core/renderers/webgl/utils/ObjectRenderer.js b/src/core/renderers/webgl/utils/ObjectRenderer.js index 3b5f432..a07a9b7 100644 --- a/src/core/renderers/webgl/utils/ObjectRenderer.js +++ b/src/core/renderers/webgl/utils/ObjectRenderer.js @@ -25,7 +25,7 @@ ObjectRenderer.prototype.stop = function () { - // flush! + this.flush(); }; ObjectRenderer.prototype.flush = function () diff --git a/src/core/renderers/webgl/utils/WebGLFastSpriteBatch.js b/src/core/renderers/webgl/utils/WebGLFastSpriteBatch.js deleted file mode 100644 index 3f37b7d..0000000 --- a/src/core/renderers/webgl/utils/WebGLFastSpriteBatch.js +++ /dev/null @@ -1,466 +0,0 @@ -/** - * @author Mat Groves - * - * Big thanks to the very clever Matt DesLauriers 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 - */ - -/** - * @class - * @private - * @namespace PIXI - * @param renderer {WebGLRenderer} The renderer this sprite batch works for. - */ -function WebGLFastSpriteBatch(renderer) -{ - /** - * The renderer instance this sprite batch operates on. - * - * @member {WebGLRenderer} - */ - this.renderer = renderer; - - /** - * - * - * @member {number} - */ - this.vertSize = 10; - - /** - * - * - * @member {number} - */ - this.vertByteSize = this.vertSize * 4; - - /** - * - * - * @member {number} - */ - this.maxSize = 6000;//Math.pow(2, 16) / this.vertSize; - - /** - * - * - * @member {number} - */ - this.size = this.maxSize; - - //the total number of floats in our batch - var numVerts = this.size * this.vertByteSize; - - //the total number of indices in our batch - var numIndices = this.maxSize * 6; - - /** - * Vertex data - * - * @member {Float32Array} - */ - this.vertices = new Float32Array(numVerts); - - /** - * Index data - * - * @member {Uint16Array} - */ - this.indices = new Uint16Array(numIndices); - - /** - * - * - * @member {object} - */ - this.vertexBuffer = null; - - /** - * - * - * @member {object} - */ - this.indexBuffer = null; - - /** - * - * - * @member {number} - */ - 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; - } - - /** - * - * - * @member {boolean} - */ - this.drawing = false; - - /** - * - * - * @member {number} - */ - this.currentBatchSize = 0; - - /** - * - * - * @member {BaseTexture} - */ - this.currentBaseTexture = null; - - /** - * - * - * @member {number} - */ - this.currentBlendMode = 0; - - /** - * - * - * @member {object} - */ - this.shader = null; - - /** - * - * - * @member {Matrix} - */ - this.matrix = null; - - // listen for context and update necessary buffers - var self = this; - this.renderer.on('context', function () - { - self.setupContext(); - }); -} - -WebGLFastSpriteBatch.prototype.constructor = WebGLFastSpriteBatch; -module.exports = WebGLFastSpriteBatch; - -/** - * Sets the WebGL Context. - * - * @param gl {WebGLContext} the current WebGL drawing context - */ -WebGLFastSpriteBatch.prototype.setupContext = function () -{ - var gl = this.renderer.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); -}; - -/** - * @param spriteBatch {SpriteBatch} The SpriteBatch container to prepare for. - */ -WebGLFastSpriteBatch.prototype.begin = function (spriteBatch) -{ - this.shader = this.renderer.shaderManager.plugins.fastShader; - - this.matrix = spriteBatch.worldTransform.toArray(true); - - this.start(); -}; - -/** - */ -WebGLFastSpriteBatch.prototype.end = function () -{ - this.flush(); -}; - -/** - * @param spriteBatch {SpriteBatch} The SpriteBatch container to render. - */ -WebGLFastSpriteBatch.prototype.render = function (spriteBatch) -{ - var children = spriteBatch.children; - var sprite = children[0]; - - // if the uvs have not updated then no point rendering just yet! - - // check texture. - if (!sprite.texture._uvs) - { - return; - } - - this.currentBaseTexture = sprite.texture.baseTexture; - - // check blend mode - if (sprite.blendMode !== this.renderer.blendModeManager.currentBlendMode) - { - this.flush(); - this.renderer.blendModeManager.setBlendMode(sprite.blendMode); - } - - for (var i=0,j= children.length; i= this.size) - { - this.flush(); - } -}; - -/** - * - */ -WebGLFastSpriteBatch.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.renderer.gl; - - // bind the current texture - if (!this.currentBaseTexture._glTextures[gl.id]) - { - this.renderer.updateTexture(this.currentBaseTexture, gl); - } - //TODO-SHOUD THIS BE ELSE??!?!?! - else - { - gl.bindTexture(gl.TEXTURE_2D, this.currentBaseTexture._glTextures[gl.id]); - } - - // upload the verts to the buffer - - if (this.currentBatchSize > ( this.size * 0.5 ) ) - { - gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.vertices); - } - else - { - var view = this.vertices.subarray(0, this.currentBatchSize * this.vertByteSize); - - 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.renderer.drawCount++; -}; - - -/** - * Ends the batch and flushes - * - */ -WebGLFastSpriteBatch.prototype.stop = function () -{ - this.flush(); -}; - -/** - * - */ -WebGLFastSpriteBatch.prototype.start = function () -{ - var gl = this.renderer.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.renderer.projection; - gl.uniform2f(this.shader.uniforms.projectionVector._location, projection.x, projection.y); - - // set the matrix - gl.uniformMatrix3fv(this.shader.uniforms.uMatrix._location, false, this.matrix); - - // set the pointers - var stride = this.vertByteSize; - - gl.vertexAttribPointer(this.shader.attributes.aVertexPosition, 2, gl.FLOAT, false, stride, 0); - gl.vertexAttribPointer(this.shader.attributes.aPositionCoord, 2, gl.FLOAT, false, stride, 2 * 4); - gl.vertexAttribPointer(this.shader.attributes.aScale, 2, gl.FLOAT, false, stride, 4 * 4); - gl.vertexAttribPointer(this.shader.attributes.aRotation, 1, gl.FLOAT, false, stride, 6 * 4); - gl.vertexAttribPointer(this.shader.attributes.aTextureCoord, 2, gl.FLOAT, false, stride, 7 * 4); - gl.vertexAttribPointer(this.shader.attributes.aColor, 1, gl.FLOAT, false, stride, 9 * 4); -}; diff --git a/src/core/sprites/SpriteBatch.js b/src/core/sprites/SpriteBatch.js index 4fe33e4..c1e674c 100644 --- a/src/core/sprites/SpriteBatch.js +++ b/src/core/sprites/SpriteBatch.js @@ -59,14 +59,23 @@ return; } - renderer.spriteBatch.stop(); + // renderer.spriteBatch.stop(); - renderer.shaderManager.setShader(renderer.shaderManager.plugins.fastShader); + // renderer.shaderManager.setShader(renderer.shaderManager.plugins.fastShader); - renderer.fastSpriteBatch.begin(this); - renderer.fastSpriteBatch.render(this); + // renderer.fastSpriteBatch.begin(this); + // renderer.fastSpriteBatch.render(this); - renderer.spriteBatch.start(); + // renderer.spriteBatch.start(); + + renderer.currentRenderer.stop(); + + renderer.shaderManager.setShader(renderer.plugins.spriteBatch.shader); + + renderer.plugins.spriteBatch.start(this); + renderer.plugins.spriteBatch.render(this); + + renderer.currentRenderer.start(); }; /** diff --git a/src/core/sprites/webgl/SpriteBatchRenderer.js b/src/core/sprites/webgl/SpriteBatchRenderer.js new file mode 100644 index 0000000..82a2318 --- /dev/null +++ b/src/core/sprites/webgl/SpriteBatchRenderer.js @@ -0,0 +1,468 @@ +var ObjectRenderer = require('../../renderers/webgl/utils/ObjectRenderer'), + Shader = require('../../renderers/webgl/shaders/Shader'), + WebGLRenderer = require('../../renderers/webgl/WebGLRenderer'), + SpriteBatchShader = require('./SpriteBatchShader'); + +/** + * @author Mat Groves + * + * Big thanks to the very clever Matt DesLauriers 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 + */ + +/** + * @class + * @private + * @namespace PIXI + * @param renderer {WebGLRenderer} The renderer this sprite batch works for. + */ +function SpriteBatchRenderer(renderer) +{ + ObjectRenderer.call(this, renderer); + + /** + * + * + * @member {number} + */ + this.vertSize = 10; + + /** + * + * + * @member {number} + */ + this.vertByteSize = this.vertSize * 4; + + /** + * + * + * @member {number} + */ + this.maxSize = 6000;//Math.pow(2, 16) / this.vertSize; + + /** + * + * + * @member {number} + */ + this.size = this.maxSize; + + //the total number of floats in our batch + var numVerts = this.size * this.vertByteSize; + + //the total number of indices in our batch + var numIndices = this.maxSize * 6; + + /** + * Vertex data + * + * @member {Float32Array} + */ + this.vertices = new Float32Array(numVerts); + + /** + * Index data + * + * @member {Uint16Array} + */ + this.indices = new Uint16Array(numIndices); + + /** + * + * + * @member {object} + */ + this.vertexBuffer = null; + + /** + * + * + * @member {object} + */ + this.indexBuffer = null; + + /** + * + * + * @member {number} + */ + 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; + } + + /** + * + * + * @member {boolean} + */ + this.drawing = false; + + /** + * + * + * @member {number} + */ + this.currentBatchSize = 0; + + /** + * + * + * @member {BaseTexture} + */ + this.currentBaseTexture = null; + + /** + * + * + * @member {number} + */ + this.currentBlendMode = 0; + + /** + * + * + * @member {object} + */ + this.shader = null; + + this.setupContext(); + + // handle when the renderer's context changes. + this.renderer.on('context', this.setupContext.bind(this)); +} + +SpriteBatchRenderer.prototype = Object.create(ObjectRenderer.prototype); +SpriteBatchRenderer.prototype.constructor = SpriteBatchRenderer; +module.exports = SpriteBatchRenderer; + +WebGLRenderer.registerPlugin('spriteBatch', SpriteBatchRenderer); + +/** + * Sets the WebGL Context. + * + * @param gl {WebGLContext} the current WebGL drawing context + */ +SpriteBatchRenderer.prototype.setupContext = function () +{ + var gl = this.renderer.gl; + + // create a couple of buffers + this.vertexBuffer = gl.createBuffer(); + this.indexBuffer = gl.createBuffer(); + + this.shader = new SpriteBatchShader(this.renderer.shaderManager); + + // 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); +}; + +/** + */ +// SpriteBatchRenderer.prototype.stop = function () +// { +// this.flush(); +// }; + +/** + * @param spriteBatch {SpriteBatch} The SpriteBatch container to render. + */ +SpriteBatchRenderer.prototype.render = function (spriteBatch) +{ + var children = spriteBatch.children; + var sprite = children[0]; + + // if the uvs have not updated then no point rendering just yet! + + // check texture. + if (!sprite.texture._uvs) + { + return; + } + + this.currentBaseTexture = sprite.texture.baseTexture; + + // check blend mode + if (sprite.blendMode !== this.renderer.blendModeManager.currentBlendMode) + { + this.flush(); + this.renderer.blendModeManager.setBlendMode(sprite.blendMode); + } + + for (var i=0,j= children.length; i= this.size) + { + this.flush(); + } +}; + +/** + * + */ +SpriteBatchRenderer.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.renderer.gl; + + // bind the current texture + if (!this.currentBaseTexture._glTextures[gl.id]) + { + this.renderer.updateTexture(this.currentBaseTexture, gl); + } + //TODO-SHOUD THIS BE ELSE??!?!?! + else + { + gl.bindTexture(gl.TEXTURE_2D, this.currentBaseTexture._glTextures[gl.id]); + } + + // upload the verts to the buffer + + if (this.currentBatchSize > ( this.size * 0.5 ) ) + { + gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.vertices); + } + else + { + var view = this.vertices.subarray(0, this.currentBatchSize * this.vertByteSize); + + 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.renderer.drawCount++; +}; + +/** + * + */ +SpriteBatchRenderer.prototype.start = function (spriteBatch) +{ + var gl = this.renderer.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.renderer.projection; + // gl.uniform2f(this.shader.uniforms.projectionVector._location, projection.x, projection.y); + gl.uniformMatrix3fv(this.shader.uniforms.projectionMatrix._location, false, this.renderer.currentRenderTarget.projectionMatrix.toArray(true)); + + // set the matrix from the spriteBatch + gl.uniformMatrix3fv(this.shader.uniforms.uMatrix._location, false, spriteBatch.worldTransform.toArray(true)); + + // set the pointers + var stride = this.vertByteSize; + + gl.vertexAttribPointer(this.shader.attributes.aVertexPosition, 2, gl.FLOAT, false, stride, 0); + gl.vertexAttribPointer(this.shader.attributes.aTextureCoord, 2, gl.FLOAT, false, stride, 2 * 4); + gl.vertexAttribPointer(this.shader.attributes.aColor, 1, gl.FLOAT, false, stride, 4 * 4); + + gl.vertexAttribPointer(this.shader.attributes.aPositionCoord, 2, gl.FLOAT, false, stride, 5 * 4); + gl.vertexAttribPointer(this.shader.attributes.aScale, 2, gl.FLOAT, false, stride, 7 * 4); + gl.vertexAttribPointer(this.shader.attributes.aRotation, 1, gl.FLOAT, false, stride, 9 * 4); +}; + +/** + * Destroys the SpriteBatch. + * + */ +SpriteBatchRenderer.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.currentBaseTexture = null; + + this.drawing = false; + + this.shader = null; +}; diff --git a/src/core/sprites/webgl/SpriteBatchShader.js b/src/core/sprites/webgl/SpriteBatchShader.js new file mode 100644 index 0000000..1f53252 --- /dev/null +++ b/src/core/sprites/webgl/SpriteBatchShader.js @@ -0,0 +1,78 @@ +var Shader = require('../../renderers/webgl/shaders/Shader'); + +/** + * @class + * @extends Shader + * @namespace PIXI + * @param shaderManager {WebGLShaderManager} The webgl shader manager this shader works for. + */ +function SpriteBatchShader(shaderManager) +{ + Shader.call(this, + shaderManager, + // vertex shader + [ + 'attribute vec2 aVertexPosition;', + 'attribute vec2 aTextureCoord;', + 'attribute float aColor;', + + 'attribute vec2 aPositionCoord;', + 'attribute vec2 aScale;', + 'attribute float aRotation;', + + 'uniform mat3 projectionMatrix;', + // 'uniform vec2 projectionVector;', + // 'uniform vec2 offsetVector;', + 'uniform mat3 uMatrix;', + + 'varying vec2 vTextureCoord;', + 'varying float vColor;', + + // 'const vec2 center = vec2(-1.0, 1.0);', + + 'void main(void){', + ' vec2 v;', + ' vec2 sv = aVertexPosition * aScale;', + ' v.x = (sv.x) * cos(aRotation) - (sv.y) * sin(aRotation);', + ' v.y = (sv.x) * sin(aRotation) + (sv.y) * cos(aRotation);', + ' v = ( uMatrix * vec3(v + aPositionCoord , 1.0) ).xy ;', + + + // ' gl_Position = vec4( ( v / projectionVector) + center , 0.0, 1.0);', + ' gl_Position = vec4((projectionMatrix * vec3(v, 1.0)).xy, 0.0, 1.0);', + + + ' vTextureCoord = aTextureCoord;', + // ' vec3 color = mod(vec3(aColor.y/65536.0, aColor.y/256.0, aColor.y), 256.0) / 256.0;', + ' vColor = aColor;', + '}' + ].join('\n'), + // fragment shader, use default + [ + 'precision lowp float;', + + 'varying vec2 vTextureCoord;', + 'varying float vColor;', + + 'uniform sampler2D uSampler;', + + 'void main(void){', + ' gl_FragColor = texture2D(uSampler, vTextureCoord) * vColor ;', + '}' + ].join('\n'), + // custom uniforms + { + uMatrix: { type: 'mat3', value: new Float32Array(9) } + }, + // custom attributes + { + aPositionCoord: 0, + aScale: 0, + aRotation: 0 + } + ); +} + +SpriteBatchShader.prototype = Object.create(Shader.prototype); +SpriteBatchShader.prototype.constructor = SpriteBatchShader; +module.exports = SpriteBatchShader; diff --git a/src/core/sprites/webgl/SpriteRenderer.js b/src/core/sprites/webgl/SpriteRenderer.js index c006ba4..4f4eab4 100644 --- a/src/core/sprites/webgl/SpriteRenderer.js +++ b/src/core/sprites/webgl/SpriteRenderer.js @@ -28,13 +28,6 @@ /** * * - * @member {WebGLRenderer} - */ - this.renderer = renderer; - - /** - * - * * @member {number} */ this.vertSize = 5; @@ -127,13 +120,6 @@ /** * * - * @member {boolean} - */ - this.dirty = true; - - /** - * - * * @member {Array} */ this.textures = []; @@ -167,6 +153,9 @@ this.shader = null; this.setupContext(); + + // handle when the renderer's context changes. + this.renderer.on('context', this.setupContext.bind(this)); } SpriteRenderer.prototype = Object.create(ObjectRenderer.prototype); @@ -349,25 +338,6 @@ var gl = this.renderer.gl; var shader; - if (this.dirty) - { - this.dirty = false; - // 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); - - // this is the same for each shader? - var stride = this.vertByteSize; - gl.vertexAttribPointer(this.shader.attributes.aVertexPosition, 2, gl.FLOAT, false, stride, 0); - gl.vertexAttribPointer(this.shader.attributes.aTextureCoord, 2, gl.FLOAT, false, stride, 2 * 4); - - // color attributes will be interpreted as unsigned bytes and normalized - gl.vertexAttribPointer(this.shader.attributes.aColor, 4, gl.UNSIGNED_BYTE, true, stride, 4 * 4); - } - // upload the verts to the buffer if (this.currentBatchSize > ( this.size * 0.5 ) ) { @@ -487,22 +457,27 @@ }; /** - * Flushes the sprite renderer's current batch. - * - */ -SpriteRenderer.prototype.stop = function () -{ - this.flush(); - this.dirty = true; -}; - -/** * Starts a new sprite batch. * */ SpriteRenderer.prototype.start = function () { - this.dirty = true; + var gl = this.renderer.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); + + // this is the same for each shader? + var stride = this.vertByteSize; + gl.vertexAttribPointer(this.shader.attributes.aVertexPosition, 2, gl.FLOAT, false, stride, 0); + gl.vertexAttribPointer(this.shader.attributes.aTextureCoord, 2, gl.FLOAT, false, stride, 2 * 4); + + // color attributes will be interpreted as unsigned bytes and normalized + gl.vertexAttribPointer(this.shader.attributes.aColor, 4, gl.UNSIGNED_BYTE, true, stride, 4 * 4); }; /** @@ -514,16 +489,21 @@ this.renderer.gl.deleteBuffer(this.vertexBuffer); this.renderer.gl.deleteBuffer(this.indexBuffer); + this.shader.destroy(); + this.renderer = null; this.vertices = null; this.positions = null; this.colors = null; this.indices = null; + + this.vertexBuffer = null; + this.indexBuffer = null; + this.currentBaseTexture = null; this.drawing = false; - this.dirty = false; this.textures = null; this.blendModes = null; diff --git a/src/core/index.js b/src/core/index.js index 1d0a398..4fc777d 100644 --- a/src/core/index.js +++ b/src/core/index.js @@ -24,6 +24,7 @@ Sprite: require('./sprites/Sprite'), SpriteBatch: require('./sprites/SpriteBatch'), SpriteRenderer: require('./sprites/webgl/SpriteRenderer'), + SpriteBatchRenderer: require('./sprites/webgl/SpriteBatchRenderer'), // primitives Graphics: require('./graphics/Graphics'), @@ -43,6 +44,7 @@ // renderers - webgl WebGLRenderer: require('./renderers/webgl/WebGLRenderer'), + WebGLShaderManager: require('./renderers/webgl/managers/WebGLShaderManager'), Shader: require('./renderers/webgl/shaders/Shader'), /** diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js index 4e82baa..13892a6 100644 --- a/src/core/renderers/webgl/WebGLRenderer.js +++ b/src/core/renderers/webgl/WebGLRenderer.js @@ -1,5 +1,4 @@ -var WebGLFastSpriteBatch = require('./utils/WebGLFastSpriteBatch'), - WebGLShaderManager = require('./managers/WebGLShaderManager'), +var WebGLShaderManager = require('./managers/WebGLShaderManager'), WebGLMaskManager = require('./managers/WebGLMaskManager'), WebGLFilterManager = require('./managers/WebGLFilterManager'), WebGLBlendModeManager = require('./managers/WebGLBlendModeManager'), @@ -184,12 +183,6 @@ this.shaderManager = new WebGLShaderManager(this); /** - * Manages the rendering of sprites - * @member {WebGLFastSpriteBatch} - */ - this.fastSpriteBatch = new WebGLFastSpriteBatch(this); - - /** * Manages the masks using the stencil buffer * @member {WebGLMaskManager} */ diff --git a/src/core/renderers/webgl/shaders/FastShader.js b/src/core/renderers/webgl/shaders/FastShader.js deleted file mode 100644 index c80d040..0000000 --- a/src/core/renderers/webgl/shaders/FastShader.js +++ /dev/null @@ -1,75 +0,0 @@ -var Shader = require('./Shader'), - WebGLShaderManager = require('../managers/WebGLShaderManager'); - -/** - * @class - * @extends Shader - * @namespace PIXI - * @param shaderManager {WebGLShaderManager} The webgl shader manager this shader works for. - */ -function FastShader(shaderManager) -{ - Shader.call(this, - shaderManager, - // vertex shader - [ - 'attribute vec2 aVertexPosition;', - 'attribute vec2 aTextureCoord;', - 'attribute float aColor;', - - 'attribute vec2 aPositionCoord;', - 'attribute vec2 aScale;', - 'attribute float aRotation;', - - 'uniform vec2 projectionVector;', - 'uniform vec2 offsetVector;', - 'uniform mat3 uMatrix;', - - 'varying vec2 vTextureCoord;', - 'varying float vColor;', - - 'const vec2 center = vec2(-1.0, 1.0);', - - 'void main(void){', - ' vec2 v;', - ' vec2 sv = aVertexPosition * aScale;', - ' v.x = (sv.x) * cos(aRotation) - (sv.y) * sin(aRotation);', - ' v.y = (sv.x) * sin(aRotation) + (sv.y) * cos(aRotation);', - ' v = ( uMatrix * vec3(v + aPositionCoord , 1.0) ).xy ;', - ' gl_Position = vec4( ( v / projectionVector) + center , 0.0, 1.0);', - ' vTextureCoord = aTextureCoord;', - // ' vec3 color = mod(vec3(aColor.y/65536.0, aColor.y/256.0, aColor.y), 256.0) / 256.0;', - ' vColor = aColor;', - '}' - ].join('\n'), - // fragment shader, use default - [ - 'precision lowp float;', - - 'varying vec2 vTextureCoord;', - 'varying float vColor;', - - 'uniform sampler2D uSampler;', - - 'void main(void){', - ' gl_FragColor = texture2D(uSampler, vTextureCoord) * vColor ;', - '}' - ].join('\n'), - // custom uniforms - { - uMatrix: { type: 'mat3', value: new Float32Array(9) } - }, - // custom attributes - { - aPositionCoord: 0, - aRotation: 0, - aScale: 0 - } - ); -} - -FastShader.prototype = Object.create(Shader.prototype); -FastShader.prototype.constructor = FastShader; -module.exports = FastShader; - -WebGLShaderManager.registerPlugin('fastShader', FastShader); diff --git a/src/core/renderers/webgl/shaders/Shader.js b/src/core/renderers/webgl/shaders/Shader.js index c60c5f9..84f321f 100644 --- a/src/core/renderers/webgl/shaders/Shader.js +++ b/src/core/renderers/webgl/shaders/Shader.js @@ -47,7 +47,9 @@ } this.attributes = { - aVertexPosition: 0 + aVertexPosition: 0, + aTextureCoord: 0, + aColor: 0 }; for (var a in customAttributes) @@ -67,7 +69,7 @@ 'attribute vec4 aColor;', 'uniform mat3 projectionMatrix;', - 'uniform vec2 projectionVector;', + // 'uniform vec2 projectionVector;', 'uniform vec2 offsetVector;', 'varying vec2 vTextureCoord;', diff --git a/src/core/renderers/webgl/utils/ObjectRenderer.js b/src/core/renderers/webgl/utils/ObjectRenderer.js index 3b5f432..a07a9b7 100644 --- a/src/core/renderers/webgl/utils/ObjectRenderer.js +++ b/src/core/renderers/webgl/utils/ObjectRenderer.js @@ -25,7 +25,7 @@ ObjectRenderer.prototype.stop = function () { - // flush! + this.flush(); }; ObjectRenderer.prototype.flush = function () diff --git a/src/core/renderers/webgl/utils/WebGLFastSpriteBatch.js b/src/core/renderers/webgl/utils/WebGLFastSpriteBatch.js deleted file mode 100644 index 3f37b7d..0000000 --- a/src/core/renderers/webgl/utils/WebGLFastSpriteBatch.js +++ /dev/null @@ -1,466 +0,0 @@ -/** - * @author Mat Groves - * - * Big thanks to the very clever Matt DesLauriers 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 - */ - -/** - * @class - * @private - * @namespace PIXI - * @param renderer {WebGLRenderer} The renderer this sprite batch works for. - */ -function WebGLFastSpriteBatch(renderer) -{ - /** - * The renderer instance this sprite batch operates on. - * - * @member {WebGLRenderer} - */ - this.renderer = renderer; - - /** - * - * - * @member {number} - */ - this.vertSize = 10; - - /** - * - * - * @member {number} - */ - this.vertByteSize = this.vertSize * 4; - - /** - * - * - * @member {number} - */ - this.maxSize = 6000;//Math.pow(2, 16) / this.vertSize; - - /** - * - * - * @member {number} - */ - this.size = this.maxSize; - - //the total number of floats in our batch - var numVerts = this.size * this.vertByteSize; - - //the total number of indices in our batch - var numIndices = this.maxSize * 6; - - /** - * Vertex data - * - * @member {Float32Array} - */ - this.vertices = new Float32Array(numVerts); - - /** - * Index data - * - * @member {Uint16Array} - */ - this.indices = new Uint16Array(numIndices); - - /** - * - * - * @member {object} - */ - this.vertexBuffer = null; - - /** - * - * - * @member {object} - */ - this.indexBuffer = null; - - /** - * - * - * @member {number} - */ - 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; - } - - /** - * - * - * @member {boolean} - */ - this.drawing = false; - - /** - * - * - * @member {number} - */ - this.currentBatchSize = 0; - - /** - * - * - * @member {BaseTexture} - */ - this.currentBaseTexture = null; - - /** - * - * - * @member {number} - */ - this.currentBlendMode = 0; - - /** - * - * - * @member {object} - */ - this.shader = null; - - /** - * - * - * @member {Matrix} - */ - this.matrix = null; - - // listen for context and update necessary buffers - var self = this; - this.renderer.on('context', function () - { - self.setupContext(); - }); -} - -WebGLFastSpriteBatch.prototype.constructor = WebGLFastSpriteBatch; -module.exports = WebGLFastSpriteBatch; - -/** - * Sets the WebGL Context. - * - * @param gl {WebGLContext} the current WebGL drawing context - */ -WebGLFastSpriteBatch.prototype.setupContext = function () -{ - var gl = this.renderer.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); -}; - -/** - * @param spriteBatch {SpriteBatch} The SpriteBatch container to prepare for. - */ -WebGLFastSpriteBatch.prototype.begin = function (spriteBatch) -{ - this.shader = this.renderer.shaderManager.plugins.fastShader; - - this.matrix = spriteBatch.worldTransform.toArray(true); - - this.start(); -}; - -/** - */ -WebGLFastSpriteBatch.prototype.end = function () -{ - this.flush(); -}; - -/** - * @param spriteBatch {SpriteBatch} The SpriteBatch container to render. - */ -WebGLFastSpriteBatch.prototype.render = function (spriteBatch) -{ - var children = spriteBatch.children; - var sprite = children[0]; - - // if the uvs have not updated then no point rendering just yet! - - // check texture. - if (!sprite.texture._uvs) - { - return; - } - - this.currentBaseTexture = sprite.texture.baseTexture; - - // check blend mode - if (sprite.blendMode !== this.renderer.blendModeManager.currentBlendMode) - { - this.flush(); - this.renderer.blendModeManager.setBlendMode(sprite.blendMode); - } - - for (var i=0,j= children.length; i= this.size) - { - this.flush(); - } -}; - -/** - * - */ -WebGLFastSpriteBatch.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.renderer.gl; - - // bind the current texture - if (!this.currentBaseTexture._glTextures[gl.id]) - { - this.renderer.updateTexture(this.currentBaseTexture, gl); - } - //TODO-SHOUD THIS BE ELSE??!?!?! - else - { - gl.bindTexture(gl.TEXTURE_2D, this.currentBaseTexture._glTextures[gl.id]); - } - - // upload the verts to the buffer - - if (this.currentBatchSize > ( this.size * 0.5 ) ) - { - gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.vertices); - } - else - { - var view = this.vertices.subarray(0, this.currentBatchSize * this.vertByteSize); - - 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.renderer.drawCount++; -}; - - -/** - * Ends the batch and flushes - * - */ -WebGLFastSpriteBatch.prototype.stop = function () -{ - this.flush(); -}; - -/** - * - */ -WebGLFastSpriteBatch.prototype.start = function () -{ - var gl = this.renderer.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.renderer.projection; - gl.uniform2f(this.shader.uniforms.projectionVector._location, projection.x, projection.y); - - // set the matrix - gl.uniformMatrix3fv(this.shader.uniforms.uMatrix._location, false, this.matrix); - - // set the pointers - var stride = this.vertByteSize; - - gl.vertexAttribPointer(this.shader.attributes.aVertexPosition, 2, gl.FLOAT, false, stride, 0); - gl.vertexAttribPointer(this.shader.attributes.aPositionCoord, 2, gl.FLOAT, false, stride, 2 * 4); - gl.vertexAttribPointer(this.shader.attributes.aScale, 2, gl.FLOAT, false, stride, 4 * 4); - gl.vertexAttribPointer(this.shader.attributes.aRotation, 1, gl.FLOAT, false, stride, 6 * 4); - gl.vertexAttribPointer(this.shader.attributes.aTextureCoord, 2, gl.FLOAT, false, stride, 7 * 4); - gl.vertexAttribPointer(this.shader.attributes.aColor, 1, gl.FLOAT, false, stride, 9 * 4); -}; diff --git a/src/core/sprites/SpriteBatch.js b/src/core/sprites/SpriteBatch.js index 4fe33e4..c1e674c 100644 --- a/src/core/sprites/SpriteBatch.js +++ b/src/core/sprites/SpriteBatch.js @@ -59,14 +59,23 @@ return; } - renderer.spriteBatch.stop(); + // renderer.spriteBatch.stop(); - renderer.shaderManager.setShader(renderer.shaderManager.plugins.fastShader); + // renderer.shaderManager.setShader(renderer.shaderManager.plugins.fastShader); - renderer.fastSpriteBatch.begin(this); - renderer.fastSpriteBatch.render(this); + // renderer.fastSpriteBatch.begin(this); + // renderer.fastSpriteBatch.render(this); - renderer.spriteBatch.start(); + // renderer.spriteBatch.start(); + + renderer.currentRenderer.stop(); + + renderer.shaderManager.setShader(renderer.plugins.spriteBatch.shader); + + renderer.plugins.spriteBatch.start(this); + renderer.plugins.spriteBatch.render(this); + + renderer.currentRenderer.start(); }; /** diff --git a/src/core/sprites/webgl/SpriteBatchRenderer.js b/src/core/sprites/webgl/SpriteBatchRenderer.js new file mode 100644 index 0000000..82a2318 --- /dev/null +++ b/src/core/sprites/webgl/SpriteBatchRenderer.js @@ -0,0 +1,468 @@ +var ObjectRenderer = require('../../renderers/webgl/utils/ObjectRenderer'), + Shader = require('../../renderers/webgl/shaders/Shader'), + WebGLRenderer = require('../../renderers/webgl/WebGLRenderer'), + SpriteBatchShader = require('./SpriteBatchShader'); + +/** + * @author Mat Groves + * + * Big thanks to the very clever Matt DesLauriers 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 + */ + +/** + * @class + * @private + * @namespace PIXI + * @param renderer {WebGLRenderer} The renderer this sprite batch works for. + */ +function SpriteBatchRenderer(renderer) +{ + ObjectRenderer.call(this, renderer); + + /** + * + * + * @member {number} + */ + this.vertSize = 10; + + /** + * + * + * @member {number} + */ + this.vertByteSize = this.vertSize * 4; + + /** + * + * + * @member {number} + */ + this.maxSize = 6000;//Math.pow(2, 16) / this.vertSize; + + /** + * + * + * @member {number} + */ + this.size = this.maxSize; + + //the total number of floats in our batch + var numVerts = this.size * this.vertByteSize; + + //the total number of indices in our batch + var numIndices = this.maxSize * 6; + + /** + * Vertex data + * + * @member {Float32Array} + */ + this.vertices = new Float32Array(numVerts); + + /** + * Index data + * + * @member {Uint16Array} + */ + this.indices = new Uint16Array(numIndices); + + /** + * + * + * @member {object} + */ + this.vertexBuffer = null; + + /** + * + * + * @member {object} + */ + this.indexBuffer = null; + + /** + * + * + * @member {number} + */ + 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; + } + + /** + * + * + * @member {boolean} + */ + this.drawing = false; + + /** + * + * + * @member {number} + */ + this.currentBatchSize = 0; + + /** + * + * + * @member {BaseTexture} + */ + this.currentBaseTexture = null; + + /** + * + * + * @member {number} + */ + this.currentBlendMode = 0; + + /** + * + * + * @member {object} + */ + this.shader = null; + + this.setupContext(); + + // handle when the renderer's context changes. + this.renderer.on('context', this.setupContext.bind(this)); +} + +SpriteBatchRenderer.prototype = Object.create(ObjectRenderer.prototype); +SpriteBatchRenderer.prototype.constructor = SpriteBatchRenderer; +module.exports = SpriteBatchRenderer; + +WebGLRenderer.registerPlugin('spriteBatch', SpriteBatchRenderer); + +/** + * Sets the WebGL Context. + * + * @param gl {WebGLContext} the current WebGL drawing context + */ +SpriteBatchRenderer.prototype.setupContext = function () +{ + var gl = this.renderer.gl; + + // create a couple of buffers + this.vertexBuffer = gl.createBuffer(); + this.indexBuffer = gl.createBuffer(); + + this.shader = new SpriteBatchShader(this.renderer.shaderManager); + + // 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); +}; + +/** + */ +// SpriteBatchRenderer.prototype.stop = function () +// { +// this.flush(); +// }; + +/** + * @param spriteBatch {SpriteBatch} The SpriteBatch container to render. + */ +SpriteBatchRenderer.prototype.render = function (spriteBatch) +{ + var children = spriteBatch.children; + var sprite = children[0]; + + // if the uvs have not updated then no point rendering just yet! + + // check texture. + if (!sprite.texture._uvs) + { + return; + } + + this.currentBaseTexture = sprite.texture.baseTexture; + + // check blend mode + if (sprite.blendMode !== this.renderer.blendModeManager.currentBlendMode) + { + this.flush(); + this.renderer.blendModeManager.setBlendMode(sprite.blendMode); + } + + for (var i=0,j= children.length; i= this.size) + { + this.flush(); + } +}; + +/** + * + */ +SpriteBatchRenderer.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.renderer.gl; + + // bind the current texture + if (!this.currentBaseTexture._glTextures[gl.id]) + { + this.renderer.updateTexture(this.currentBaseTexture, gl); + } + //TODO-SHOUD THIS BE ELSE??!?!?! + else + { + gl.bindTexture(gl.TEXTURE_2D, this.currentBaseTexture._glTextures[gl.id]); + } + + // upload the verts to the buffer + + if (this.currentBatchSize > ( this.size * 0.5 ) ) + { + gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.vertices); + } + else + { + var view = this.vertices.subarray(0, this.currentBatchSize * this.vertByteSize); + + 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.renderer.drawCount++; +}; + +/** + * + */ +SpriteBatchRenderer.prototype.start = function (spriteBatch) +{ + var gl = this.renderer.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.renderer.projection; + // gl.uniform2f(this.shader.uniforms.projectionVector._location, projection.x, projection.y); + gl.uniformMatrix3fv(this.shader.uniforms.projectionMatrix._location, false, this.renderer.currentRenderTarget.projectionMatrix.toArray(true)); + + // set the matrix from the spriteBatch + gl.uniformMatrix3fv(this.shader.uniforms.uMatrix._location, false, spriteBatch.worldTransform.toArray(true)); + + // set the pointers + var stride = this.vertByteSize; + + gl.vertexAttribPointer(this.shader.attributes.aVertexPosition, 2, gl.FLOAT, false, stride, 0); + gl.vertexAttribPointer(this.shader.attributes.aTextureCoord, 2, gl.FLOAT, false, stride, 2 * 4); + gl.vertexAttribPointer(this.shader.attributes.aColor, 1, gl.FLOAT, false, stride, 4 * 4); + + gl.vertexAttribPointer(this.shader.attributes.aPositionCoord, 2, gl.FLOAT, false, stride, 5 * 4); + gl.vertexAttribPointer(this.shader.attributes.aScale, 2, gl.FLOAT, false, stride, 7 * 4); + gl.vertexAttribPointer(this.shader.attributes.aRotation, 1, gl.FLOAT, false, stride, 9 * 4); +}; + +/** + * Destroys the SpriteBatch. + * + */ +SpriteBatchRenderer.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.currentBaseTexture = null; + + this.drawing = false; + + this.shader = null; +}; diff --git a/src/core/sprites/webgl/SpriteBatchShader.js b/src/core/sprites/webgl/SpriteBatchShader.js new file mode 100644 index 0000000..1f53252 --- /dev/null +++ b/src/core/sprites/webgl/SpriteBatchShader.js @@ -0,0 +1,78 @@ +var Shader = require('../../renderers/webgl/shaders/Shader'); + +/** + * @class + * @extends Shader + * @namespace PIXI + * @param shaderManager {WebGLShaderManager} The webgl shader manager this shader works for. + */ +function SpriteBatchShader(shaderManager) +{ + Shader.call(this, + shaderManager, + // vertex shader + [ + 'attribute vec2 aVertexPosition;', + 'attribute vec2 aTextureCoord;', + 'attribute float aColor;', + + 'attribute vec2 aPositionCoord;', + 'attribute vec2 aScale;', + 'attribute float aRotation;', + + 'uniform mat3 projectionMatrix;', + // 'uniform vec2 projectionVector;', + // 'uniform vec2 offsetVector;', + 'uniform mat3 uMatrix;', + + 'varying vec2 vTextureCoord;', + 'varying float vColor;', + + // 'const vec2 center = vec2(-1.0, 1.0);', + + 'void main(void){', + ' vec2 v;', + ' vec2 sv = aVertexPosition * aScale;', + ' v.x = (sv.x) * cos(aRotation) - (sv.y) * sin(aRotation);', + ' v.y = (sv.x) * sin(aRotation) + (sv.y) * cos(aRotation);', + ' v = ( uMatrix * vec3(v + aPositionCoord , 1.0) ).xy ;', + + + // ' gl_Position = vec4( ( v / projectionVector) + center , 0.0, 1.0);', + ' gl_Position = vec4((projectionMatrix * vec3(v, 1.0)).xy, 0.0, 1.0);', + + + ' vTextureCoord = aTextureCoord;', + // ' vec3 color = mod(vec3(aColor.y/65536.0, aColor.y/256.0, aColor.y), 256.0) / 256.0;', + ' vColor = aColor;', + '}' + ].join('\n'), + // fragment shader, use default + [ + 'precision lowp float;', + + 'varying vec2 vTextureCoord;', + 'varying float vColor;', + + 'uniform sampler2D uSampler;', + + 'void main(void){', + ' gl_FragColor = texture2D(uSampler, vTextureCoord) * vColor ;', + '}' + ].join('\n'), + // custom uniforms + { + uMatrix: { type: 'mat3', value: new Float32Array(9) } + }, + // custom attributes + { + aPositionCoord: 0, + aScale: 0, + aRotation: 0 + } + ); +} + +SpriteBatchShader.prototype = Object.create(Shader.prototype); +SpriteBatchShader.prototype.constructor = SpriteBatchShader; +module.exports = SpriteBatchShader; diff --git a/src/core/sprites/webgl/SpriteRenderer.js b/src/core/sprites/webgl/SpriteRenderer.js index c006ba4..4f4eab4 100644 --- a/src/core/sprites/webgl/SpriteRenderer.js +++ b/src/core/sprites/webgl/SpriteRenderer.js @@ -28,13 +28,6 @@ /** * * - * @member {WebGLRenderer} - */ - this.renderer = renderer; - - /** - * - * * @member {number} */ this.vertSize = 5; @@ -127,13 +120,6 @@ /** * * - * @member {boolean} - */ - this.dirty = true; - - /** - * - * * @member {Array} */ this.textures = []; @@ -167,6 +153,9 @@ this.shader = null; this.setupContext(); + + // handle when the renderer's context changes. + this.renderer.on('context', this.setupContext.bind(this)); } SpriteRenderer.prototype = Object.create(ObjectRenderer.prototype); @@ -349,25 +338,6 @@ var gl = this.renderer.gl; var shader; - if (this.dirty) - { - this.dirty = false; - // 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); - - // this is the same for each shader? - var stride = this.vertByteSize; - gl.vertexAttribPointer(this.shader.attributes.aVertexPosition, 2, gl.FLOAT, false, stride, 0); - gl.vertexAttribPointer(this.shader.attributes.aTextureCoord, 2, gl.FLOAT, false, stride, 2 * 4); - - // color attributes will be interpreted as unsigned bytes and normalized - gl.vertexAttribPointer(this.shader.attributes.aColor, 4, gl.UNSIGNED_BYTE, true, stride, 4 * 4); - } - // upload the verts to the buffer if (this.currentBatchSize > ( this.size * 0.5 ) ) { @@ -487,22 +457,27 @@ }; /** - * Flushes the sprite renderer's current batch. - * - */ -SpriteRenderer.prototype.stop = function () -{ - this.flush(); - this.dirty = true; -}; - -/** * Starts a new sprite batch. * */ SpriteRenderer.prototype.start = function () { - this.dirty = true; + var gl = this.renderer.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); + + // this is the same for each shader? + var stride = this.vertByteSize; + gl.vertexAttribPointer(this.shader.attributes.aVertexPosition, 2, gl.FLOAT, false, stride, 0); + gl.vertexAttribPointer(this.shader.attributes.aTextureCoord, 2, gl.FLOAT, false, stride, 2 * 4); + + // color attributes will be interpreted as unsigned bytes and normalized + gl.vertexAttribPointer(this.shader.attributes.aColor, 4, gl.UNSIGNED_BYTE, true, stride, 4 * 4); }; /** @@ -514,16 +489,21 @@ this.renderer.gl.deleteBuffer(this.vertexBuffer); this.renderer.gl.deleteBuffer(this.indexBuffer); + this.shader.destroy(); + this.renderer = null; this.vertices = null; this.positions = null; this.colors = null; this.indices = null; + + this.vertexBuffer = null; + this.indexBuffer = null; + this.currentBaseTexture = null; this.drawing = false; - this.dirty = false; this.textures = null; this.blendModes = null; diff --git a/src/core/sprites/webgl/SpriteShader.js b/src/core/sprites/webgl/SpriteShader.js index 7d581ea..563ecdf 100644 --- a/src/core/sprites/webgl/SpriteShader.js +++ b/src/core/sprites/webgl/SpriteShader.js @@ -1,5 +1,4 @@ -var Shader = require('../../renderers/webgl/shaders/Shader'), - WebGLShaderManager = require('../../renderers/webgl/managers/WebGLShaderManager'); +var Shader = require('../../renderers/webgl/shaders/Shader'); /** * @class @@ -41,5 +40,3 @@ SpriteShader.prototype = Object.create(Shader.prototype); SpriteShader.prototype.constructor = SpriteShader; module.exports = SpriteShader; - -WebGLShaderManager.registerPlugin('spriteShader', SpriteShader); diff --git a/src/core/index.js b/src/core/index.js index 1d0a398..4fc777d 100644 --- a/src/core/index.js +++ b/src/core/index.js @@ -24,6 +24,7 @@ Sprite: require('./sprites/Sprite'), SpriteBatch: require('./sprites/SpriteBatch'), SpriteRenderer: require('./sprites/webgl/SpriteRenderer'), + SpriteBatchRenderer: require('./sprites/webgl/SpriteBatchRenderer'), // primitives Graphics: require('./graphics/Graphics'), @@ -43,6 +44,7 @@ // renderers - webgl WebGLRenderer: require('./renderers/webgl/WebGLRenderer'), + WebGLShaderManager: require('./renderers/webgl/managers/WebGLShaderManager'), Shader: require('./renderers/webgl/shaders/Shader'), /** diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js index 4e82baa..13892a6 100644 --- a/src/core/renderers/webgl/WebGLRenderer.js +++ b/src/core/renderers/webgl/WebGLRenderer.js @@ -1,5 +1,4 @@ -var WebGLFastSpriteBatch = require('./utils/WebGLFastSpriteBatch'), - WebGLShaderManager = require('./managers/WebGLShaderManager'), +var WebGLShaderManager = require('./managers/WebGLShaderManager'), WebGLMaskManager = require('./managers/WebGLMaskManager'), WebGLFilterManager = require('./managers/WebGLFilterManager'), WebGLBlendModeManager = require('./managers/WebGLBlendModeManager'), @@ -184,12 +183,6 @@ this.shaderManager = new WebGLShaderManager(this); /** - * Manages the rendering of sprites - * @member {WebGLFastSpriteBatch} - */ - this.fastSpriteBatch = new WebGLFastSpriteBatch(this); - - /** * Manages the masks using the stencil buffer * @member {WebGLMaskManager} */ diff --git a/src/core/renderers/webgl/shaders/FastShader.js b/src/core/renderers/webgl/shaders/FastShader.js deleted file mode 100644 index c80d040..0000000 --- a/src/core/renderers/webgl/shaders/FastShader.js +++ /dev/null @@ -1,75 +0,0 @@ -var Shader = require('./Shader'), - WebGLShaderManager = require('../managers/WebGLShaderManager'); - -/** - * @class - * @extends Shader - * @namespace PIXI - * @param shaderManager {WebGLShaderManager} The webgl shader manager this shader works for. - */ -function FastShader(shaderManager) -{ - Shader.call(this, - shaderManager, - // vertex shader - [ - 'attribute vec2 aVertexPosition;', - 'attribute vec2 aTextureCoord;', - 'attribute float aColor;', - - 'attribute vec2 aPositionCoord;', - 'attribute vec2 aScale;', - 'attribute float aRotation;', - - 'uniform vec2 projectionVector;', - 'uniform vec2 offsetVector;', - 'uniform mat3 uMatrix;', - - 'varying vec2 vTextureCoord;', - 'varying float vColor;', - - 'const vec2 center = vec2(-1.0, 1.0);', - - 'void main(void){', - ' vec2 v;', - ' vec2 sv = aVertexPosition * aScale;', - ' v.x = (sv.x) * cos(aRotation) - (sv.y) * sin(aRotation);', - ' v.y = (sv.x) * sin(aRotation) + (sv.y) * cos(aRotation);', - ' v = ( uMatrix * vec3(v + aPositionCoord , 1.0) ).xy ;', - ' gl_Position = vec4( ( v / projectionVector) + center , 0.0, 1.0);', - ' vTextureCoord = aTextureCoord;', - // ' vec3 color = mod(vec3(aColor.y/65536.0, aColor.y/256.0, aColor.y), 256.0) / 256.0;', - ' vColor = aColor;', - '}' - ].join('\n'), - // fragment shader, use default - [ - 'precision lowp float;', - - 'varying vec2 vTextureCoord;', - 'varying float vColor;', - - 'uniform sampler2D uSampler;', - - 'void main(void){', - ' gl_FragColor = texture2D(uSampler, vTextureCoord) * vColor ;', - '}' - ].join('\n'), - // custom uniforms - { - uMatrix: { type: 'mat3', value: new Float32Array(9) } - }, - // custom attributes - { - aPositionCoord: 0, - aRotation: 0, - aScale: 0 - } - ); -} - -FastShader.prototype = Object.create(Shader.prototype); -FastShader.prototype.constructor = FastShader; -module.exports = FastShader; - -WebGLShaderManager.registerPlugin('fastShader', FastShader); diff --git a/src/core/renderers/webgl/shaders/Shader.js b/src/core/renderers/webgl/shaders/Shader.js index c60c5f9..84f321f 100644 --- a/src/core/renderers/webgl/shaders/Shader.js +++ b/src/core/renderers/webgl/shaders/Shader.js @@ -47,7 +47,9 @@ } this.attributes = { - aVertexPosition: 0 + aVertexPosition: 0, + aTextureCoord: 0, + aColor: 0 }; for (var a in customAttributes) @@ -67,7 +69,7 @@ 'attribute vec4 aColor;', 'uniform mat3 projectionMatrix;', - 'uniform vec2 projectionVector;', + // 'uniform vec2 projectionVector;', 'uniform vec2 offsetVector;', 'varying vec2 vTextureCoord;', diff --git a/src/core/renderers/webgl/utils/ObjectRenderer.js b/src/core/renderers/webgl/utils/ObjectRenderer.js index 3b5f432..a07a9b7 100644 --- a/src/core/renderers/webgl/utils/ObjectRenderer.js +++ b/src/core/renderers/webgl/utils/ObjectRenderer.js @@ -25,7 +25,7 @@ ObjectRenderer.prototype.stop = function () { - // flush! + this.flush(); }; ObjectRenderer.prototype.flush = function () diff --git a/src/core/renderers/webgl/utils/WebGLFastSpriteBatch.js b/src/core/renderers/webgl/utils/WebGLFastSpriteBatch.js deleted file mode 100644 index 3f37b7d..0000000 --- a/src/core/renderers/webgl/utils/WebGLFastSpriteBatch.js +++ /dev/null @@ -1,466 +0,0 @@ -/** - * @author Mat Groves - * - * Big thanks to the very clever Matt DesLauriers 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 - */ - -/** - * @class - * @private - * @namespace PIXI - * @param renderer {WebGLRenderer} The renderer this sprite batch works for. - */ -function WebGLFastSpriteBatch(renderer) -{ - /** - * The renderer instance this sprite batch operates on. - * - * @member {WebGLRenderer} - */ - this.renderer = renderer; - - /** - * - * - * @member {number} - */ - this.vertSize = 10; - - /** - * - * - * @member {number} - */ - this.vertByteSize = this.vertSize * 4; - - /** - * - * - * @member {number} - */ - this.maxSize = 6000;//Math.pow(2, 16) / this.vertSize; - - /** - * - * - * @member {number} - */ - this.size = this.maxSize; - - //the total number of floats in our batch - var numVerts = this.size * this.vertByteSize; - - //the total number of indices in our batch - var numIndices = this.maxSize * 6; - - /** - * Vertex data - * - * @member {Float32Array} - */ - this.vertices = new Float32Array(numVerts); - - /** - * Index data - * - * @member {Uint16Array} - */ - this.indices = new Uint16Array(numIndices); - - /** - * - * - * @member {object} - */ - this.vertexBuffer = null; - - /** - * - * - * @member {object} - */ - this.indexBuffer = null; - - /** - * - * - * @member {number} - */ - 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; - } - - /** - * - * - * @member {boolean} - */ - this.drawing = false; - - /** - * - * - * @member {number} - */ - this.currentBatchSize = 0; - - /** - * - * - * @member {BaseTexture} - */ - this.currentBaseTexture = null; - - /** - * - * - * @member {number} - */ - this.currentBlendMode = 0; - - /** - * - * - * @member {object} - */ - this.shader = null; - - /** - * - * - * @member {Matrix} - */ - this.matrix = null; - - // listen for context and update necessary buffers - var self = this; - this.renderer.on('context', function () - { - self.setupContext(); - }); -} - -WebGLFastSpriteBatch.prototype.constructor = WebGLFastSpriteBatch; -module.exports = WebGLFastSpriteBatch; - -/** - * Sets the WebGL Context. - * - * @param gl {WebGLContext} the current WebGL drawing context - */ -WebGLFastSpriteBatch.prototype.setupContext = function () -{ - var gl = this.renderer.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); -}; - -/** - * @param spriteBatch {SpriteBatch} The SpriteBatch container to prepare for. - */ -WebGLFastSpriteBatch.prototype.begin = function (spriteBatch) -{ - this.shader = this.renderer.shaderManager.plugins.fastShader; - - this.matrix = spriteBatch.worldTransform.toArray(true); - - this.start(); -}; - -/** - */ -WebGLFastSpriteBatch.prototype.end = function () -{ - this.flush(); -}; - -/** - * @param spriteBatch {SpriteBatch} The SpriteBatch container to render. - */ -WebGLFastSpriteBatch.prototype.render = function (spriteBatch) -{ - var children = spriteBatch.children; - var sprite = children[0]; - - // if the uvs have not updated then no point rendering just yet! - - // check texture. - if (!sprite.texture._uvs) - { - return; - } - - this.currentBaseTexture = sprite.texture.baseTexture; - - // check blend mode - if (sprite.blendMode !== this.renderer.blendModeManager.currentBlendMode) - { - this.flush(); - this.renderer.blendModeManager.setBlendMode(sprite.blendMode); - } - - for (var i=0,j= children.length; i= this.size) - { - this.flush(); - } -}; - -/** - * - */ -WebGLFastSpriteBatch.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.renderer.gl; - - // bind the current texture - if (!this.currentBaseTexture._glTextures[gl.id]) - { - this.renderer.updateTexture(this.currentBaseTexture, gl); - } - //TODO-SHOUD THIS BE ELSE??!?!?! - else - { - gl.bindTexture(gl.TEXTURE_2D, this.currentBaseTexture._glTextures[gl.id]); - } - - // upload the verts to the buffer - - if (this.currentBatchSize > ( this.size * 0.5 ) ) - { - gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.vertices); - } - else - { - var view = this.vertices.subarray(0, this.currentBatchSize * this.vertByteSize); - - 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.renderer.drawCount++; -}; - - -/** - * Ends the batch and flushes - * - */ -WebGLFastSpriteBatch.prototype.stop = function () -{ - this.flush(); -}; - -/** - * - */ -WebGLFastSpriteBatch.prototype.start = function () -{ - var gl = this.renderer.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.renderer.projection; - gl.uniform2f(this.shader.uniforms.projectionVector._location, projection.x, projection.y); - - // set the matrix - gl.uniformMatrix3fv(this.shader.uniforms.uMatrix._location, false, this.matrix); - - // set the pointers - var stride = this.vertByteSize; - - gl.vertexAttribPointer(this.shader.attributes.aVertexPosition, 2, gl.FLOAT, false, stride, 0); - gl.vertexAttribPointer(this.shader.attributes.aPositionCoord, 2, gl.FLOAT, false, stride, 2 * 4); - gl.vertexAttribPointer(this.shader.attributes.aScale, 2, gl.FLOAT, false, stride, 4 * 4); - gl.vertexAttribPointer(this.shader.attributes.aRotation, 1, gl.FLOAT, false, stride, 6 * 4); - gl.vertexAttribPointer(this.shader.attributes.aTextureCoord, 2, gl.FLOAT, false, stride, 7 * 4); - gl.vertexAttribPointer(this.shader.attributes.aColor, 1, gl.FLOAT, false, stride, 9 * 4); -}; diff --git a/src/core/sprites/SpriteBatch.js b/src/core/sprites/SpriteBatch.js index 4fe33e4..c1e674c 100644 --- a/src/core/sprites/SpriteBatch.js +++ b/src/core/sprites/SpriteBatch.js @@ -59,14 +59,23 @@ return; } - renderer.spriteBatch.stop(); + // renderer.spriteBatch.stop(); - renderer.shaderManager.setShader(renderer.shaderManager.plugins.fastShader); + // renderer.shaderManager.setShader(renderer.shaderManager.plugins.fastShader); - renderer.fastSpriteBatch.begin(this); - renderer.fastSpriteBatch.render(this); + // renderer.fastSpriteBatch.begin(this); + // renderer.fastSpriteBatch.render(this); - renderer.spriteBatch.start(); + // renderer.spriteBatch.start(); + + renderer.currentRenderer.stop(); + + renderer.shaderManager.setShader(renderer.plugins.spriteBatch.shader); + + renderer.plugins.spriteBatch.start(this); + renderer.plugins.spriteBatch.render(this); + + renderer.currentRenderer.start(); }; /** diff --git a/src/core/sprites/webgl/SpriteBatchRenderer.js b/src/core/sprites/webgl/SpriteBatchRenderer.js new file mode 100644 index 0000000..82a2318 --- /dev/null +++ b/src/core/sprites/webgl/SpriteBatchRenderer.js @@ -0,0 +1,468 @@ +var ObjectRenderer = require('../../renderers/webgl/utils/ObjectRenderer'), + Shader = require('../../renderers/webgl/shaders/Shader'), + WebGLRenderer = require('../../renderers/webgl/WebGLRenderer'), + SpriteBatchShader = require('./SpriteBatchShader'); + +/** + * @author Mat Groves + * + * Big thanks to the very clever Matt DesLauriers 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 + */ + +/** + * @class + * @private + * @namespace PIXI + * @param renderer {WebGLRenderer} The renderer this sprite batch works for. + */ +function SpriteBatchRenderer(renderer) +{ + ObjectRenderer.call(this, renderer); + + /** + * + * + * @member {number} + */ + this.vertSize = 10; + + /** + * + * + * @member {number} + */ + this.vertByteSize = this.vertSize * 4; + + /** + * + * + * @member {number} + */ + this.maxSize = 6000;//Math.pow(2, 16) / this.vertSize; + + /** + * + * + * @member {number} + */ + this.size = this.maxSize; + + //the total number of floats in our batch + var numVerts = this.size * this.vertByteSize; + + //the total number of indices in our batch + var numIndices = this.maxSize * 6; + + /** + * Vertex data + * + * @member {Float32Array} + */ + this.vertices = new Float32Array(numVerts); + + /** + * Index data + * + * @member {Uint16Array} + */ + this.indices = new Uint16Array(numIndices); + + /** + * + * + * @member {object} + */ + this.vertexBuffer = null; + + /** + * + * + * @member {object} + */ + this.indexBuffer = null; + + /** + * + * + * @member {number} + */ + 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; + } + + /** + * + * + * @member {boolean} + */ + this.drawing = false; + + /** + * + * + * @member {number} + */ + this.currentBatchSize = 0; + + /** + * + * + * @member {BaseTexture} + */ + this.currentBaseTexture = null; + + /** + * + * + * @member {number} + */ + this.currentBlendMode = 0; + + /** + * + * + * @member {object} + */ + this.shader = null; + + this.setupContext(); + + // handle when the renderer's context changes. + this.renderer.on('context', this.setupContext.bind(this)); +} + +SpriteBatchRenderer.prototype = Object.create(ObjectRenderer.prototype); +SpriteBatchRenderer.prototype.constructor = SpriteBatchRenderer; +module.exports = SpriteBatchRenderer; + +WebGLRenderer.registerPlugin('spriteBatch', SpriteBatchRenderer); + +/** + * Sets the WebGL Context. + * + * @param gl {WebGLContext} the current WebGL drawing context + */ +SpriteBatchRenderer.prototype.setupContext = function () +{ + var gl = this.renderer.gl; + + // create a couple of buffers + this.vertexBuffer = gl.createBuffer(); + this.indexBuffer = gl.createBuffer(); + + this.shader = new SpriteBatchShader(this.renderer.shaderManager); + + // 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); +}; + +/** + */ +// SpriteBatchRenderer.prototype.stop = function () +// { +// this.flush(); +// }; + +/** + * @param spriteBatch {SpriteBatch} The SpriteBatch container to render. + */ +SpriteBatchRenderer.prototype.render = function (spriteBatch) +{ + var children = spriteBatch.children; + var sprite = children[0]; + + // if the uvs have not updated then no point rendering just yet! + + // check texture. + if (!sprite.texture._uvs) + { + return; + } + + this.currentBaseTexture = sprite.texture.baseTexture; + + // check blend mode + if (sprite.blendMode !== this.renderer.blendModeManager.currentBlendMode) + { + this.flush(); + this.renderer.blendModeManager.setBlendMode(sprite.blendMode); + } + + for (var i=0,j= children.length; i= this.size) + { + this.flush(); + } +}; + +/** + * + */ +SpriteBatchRenderer.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.renderer.gl; + + // bind the current texture + if (!this.currentBaseTexture._glTextures[gl.id]) + { + this.renderer.updateTexture(this.currentBaseTexture, gl); + } + //TODO-SHOUD THIS BE ELSE??!?!?! + else + { + gl.bindTexture(gl.TEXTURE_2D, this.currentBaseTexture._glTextures[gl.id]); + } + + // upload the verts to the buffer + + if (this.currentBatchSize > ( this.size * 0.5 ) ) + { + gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.vertices); + } + else + { + var view = this.vertices.subarray(0, this.currentBatchSize * this.vertByteSize); + + 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.renderer.drawCount++; +}; + +/** + * + */ +SpriteBatchRenderer.prototype.start = function (spriteBatch) +{ + var gl = this.renderer.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.renderer.projection; + // gl.uniform2f(this.shader.uniforms.projectionVector._location, projection.x, projection.y); + gl.uniformMatrix3fv(this.shader.uniforms.projectionMatrix._location, false, this.renderer.currentRenderTarget.projectionMatrix.toArray(true)); + + // set the matrix from the spriteBatch + gl.uniformMatrix3fv(this.shader.uniforms.uMatrix._location, false, spriteBatch.worldTransform.toArray(true)); + + // set the pointers + var stride = this.vertByteSize; + + gl.vertexAttribPointer(this.shader.attributes.aVertexPosition, 2, gl.FLOAT, false, stride, 0); + gl.vertexAttribPointer(this.shader.attributes.aTextureCoord, 2, gl.FLOAT, false, stride, 2 * 4); + gl.vertexAttribPointer(this.shader.attributes.aColor, 1, gl.FLOAT, false, stride, 4 * 4); + + gl.vertexAttribPointer(this.shader.attributes.aPositionCoord, 2, gl.FLOAT, false, stride, 5 * 4); + gl.vertexAttribPointer(this.shader.attributes.aScale, 2, gl.FLOAT, false, stride, 7 * 4); + gl.vertexAttribPointer(this.shader.attributes.aRotation, 1, gl.FLOAT, false, stride, 9 * 4); +}; + +/** + * Destroys the SpriteBatch. + * + */ +SpriteBatchRenderer.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.currentBaseTexture = null; + + this.drawing = false; + + this.shader = null; +}; diff --git a/src/core/sprites/webgl/SpriteBatchShader.js b/src/core/sprites/webgl/SpriteBatchShader.js new file mode 100644 index 0000000..1f53252 --- /dev/null +++ b/src/core/sprites/webgl/SpriteBatchShader.js @@ -0,0 +1,78 @@ +var Shader = require('../../renderers/webgl/shaders/Shader'); + +/** + * @class + * @extends Shader + * @namespace PIXI + * @param shaderManager {WebGLShaderManager} The webgl shader manager this shader works for. + */ +function SpriteBatchShader(shaderManager) +{ + Shader.call(this, + shaderManager, + // vertex shader + [ + 'attribute vec2 aVertexPosition;', + 'attribute vec2 aTextureCoord;', + 'attribute float aColor;', + + 'attribute vec2 aPositionCoord;', + 'attribute vec2 aScale;', + 'attribute float aRotation;', + + 'uniform mat3 projectionMatrix;', + // 'uniform vec2 projectionVector;', + // 'uniform vec2 offsetVector;', + 'uniform mat3 uMatrix;', + + 'varying vec2 vTextureCoord;', + 'varying float vColor;', + + // 'const vec2 center = vec2(-1.0, 1.0);', + + 'void main(void){', + ' vec2 v;', + ' vec2 sv = aVertexPosition * aScale;', + ' v.x = (sv.x) * cos(aRotation) - (sv.y) * sin(aRotation);', + ' v.y = (sv.x) * sin(aRotation) + (sv.y) * cos(aRotation);', + ' v = ( uMatrix * vec3(v + aPositionCoord , 1.0) ).xy ;', + + + // ' gl_Position = vec4( ( v / projectionVector) + center , 0.0, 1.0);', + ' gl_Position = vec4((projectionMatrix * vec3(v, 1.0)).xy, 0.0, 1.0);', + + + ' vTextureCoord = aTextureCoord;', + // ' vec3 color = mod(vec3(aColor.y/65536.0, aColor.y/256.0, aColor.y), 256.0) / 256.0;', + ' vColor = aColor;', + '}' + ].join('\n'), + // fragment shader, use default + [ + 'precision lowp float;', + + 'varying vec2 vTextureCoord;', + 'varying float vColor;', + + 'uniform sampler2D uSampler;', + + 'void main(void){', + ' gl_FragColor = texture2D(uSampler, vTextureCoord) * vColor ;', + '}' + ].join('\n'), + // custom uniforms + { + uMatrix: { type: 'mat3', value: new Float32Array(9) } + }, + // custom attributes + { + aPositionCoord: 0, + aScale: 0, + aRotation: 0 + } + ); +} + +SpriteBatchShader.prototype = Object.create(Shader.prototype); +SpriteBatchShader.prototype.constructor = SpriteBatchShader; +module.exports = SpriteBatchShader; diff --git a/src/core/sprites/webgl/SpriteRenderer.js b/src/core/sprites/webgl/SpriteRenderer.js index c006ba4..4f4eab4 100644 --- a/src/core/sprites/webgl/SpriteRenderer.js +++ b/src/core/sprites/webgl/SpriteRenderer.js @@ -28,13 +28,6 @@ /** * * - * @member {WebGLRenderer} - */ - this.renderer = renderer; - - /** - * - * * @member {number} */ this.vertSize = 5; @@ -127,13 +120,6 @@ /** * * - * @member {boolean} - */ - this.dirty = true; - - /** - * - * * @member {Array} */ this.textures = []; @@ -167,6 +153,9 @@ this.shader = null; this.setupContext(); + + // handle when the renderer's context changes. + this.renderer.on('context', this.setupContext.bind(this)); } SpriteRenderer.prototype = Object.create(ObjectRenderer.prototype); @@ -349,25 +338,6 @@ var gl = this.renderer.gl; var shader; - if (this.dirty) - { - this.dirty = false; - // 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); - - // this is the same for each shader? - var stride = this.vertByteSize; - gl.vertexAttribPointer(this.shader.attributes.aVertexPosition, 2, gl.FLOAT, false, stride, 0); - gl.vertexAttribPointer(this.shader.attributes.aTextureCoord, 2, gl.FLOAT, false, stride, 2 * 4); - - // color attributes will be interpreted as unsigned bytes and normalized - gl.vertexAttribPointer(this.shader.attributes.aColor, 4, gl.UNSIGNED_BYTE, true, stride, 4 * 4); - } - // upload the verts to the buffer if (this.currentBatchSize > ( this.size * 0.5 ) ) { @@ -487,22 +457,27 @@ }; /** - * Flushes the sprite renderer's current batch. - * - */ -SpriteRenderer.prototype.stop = function () -{ - this.flush(); - this.dirty = true; -}; - -/** * Starts a new sprite batch. * */ SpriteRenderer.prototype.start = function () { - this.dirty = true; + var gl = this.renderer.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); + + // this is the same for each shader? + var stride = this.vertByteSize; + gl.vertexAttribPointer(this.shader.attributes.aVertexPosition, 2, gl.FLOAT, false, stride, 0); + gl.vertexAttribPointer(this.shader.attributes.aTextureCoord, 2, gl.FLOAT, false, stride, 2 * 4); + + // color attributes will be interpreted as unsigned bytes and normalized + gl.vertexAttribPointer(this.shader.attributes.aColor, 4, gl.UNSIGNED_BYTE, true, stride, 4 * 4); }; /** @@ -514,16 +489,21 @@ this.renderer.gl.deleteBuffer(this.vertexBuffer); this.renderer.gl.deleteBuffer(this.indexBuffer); + this.shader.destroy(); + this.renderer = null; this.vertices = null; this.positions = null; this.colors = null; this.indices = null; + + this.vertexBuffer = null; + this.indexBuffer = null; + this.currentBaseTexture = null; this.drawing = false; - this.dirty = false; this.textures = null; this.blendModes = null; diff --git a/src/core/sprites/webgl/SpriteShader.js b/src/core/sprites/webgl/SpriteShader.js index 7d581ea..563ecdf 100644 --- a/src/core/sprites/webgl/SpriteShader.js +++ b/src/core/sprites/webgl/SpriteShader.js @@ -1,5 +1,4 @@ -var Shader = require('../../renderers/webgl/shaders/Shader'), - WebGLShaderManager = require('../../renderers/webgl/managers/WebGLShaderManager'); +var Shader = require('../../renderers/webgl/shaders/Shader'); /** * @class @@ -41,5 +40,3 @@ SpriteShader.prototype = Object.create(Shader.prototype); SpriteShader.prototype.constructor = SpriteShader; module.exports = SpriteShader; - -WebGLShaderManager.registerPlugin('spriteShader', SpriteShader); diff --git a/src/core/utils/EventTarget.js b/src/core/utils/EventTarget.js deleted file mode 100644 index 671a151..0000000 --- a/src/core/utils/EventTarget.js +++ /dev/null @@ -1,196 +0,0 @@ -var EventData = require('./EventData'); - -/** - * Mixins event emitter functionality to an object. - * - * @mixin - * @namespace PIXI - * @example - * function MyEmitter() {} - * - * eventTarget.mixin(MyEmitter.prototype); - * - * var em = new MyEmitter(); - * em.emit('eventName', 'some data', 'some more data', {}, null, ...); - */ -function eventTarget(obj) -{ - /** - * Return a list of assigned event listeners. - * - * @param eventName {string} The events that should be listed. - * @return {Array} An array of listener functions - */ - obj.listeners = function listeners(eventName) - { - this._listeners = this._listeners || {}; - - return this._listeners[eventName] ? this._listeners[eventName].slice() : []; - }; - - /** - * Emit an event to all registered event listeners. - * - * @alias dispatchEvent - * @param eventName {string} The name of the event. - * @return {boolean} Indication if we've emitted an event. - */ - obj.emit = obj.dispatchEvent = function emit(eventName, data) - { - this._listeners = this._listeners || {}; - - // fast return when there are no listeners - if (!this._listeners[eventName]) - { - return; - } - - //backwards compat with old method ".emit({ type: 'something' })" - if (typeof eventName === 'object') - { - data = eventName; - eventName = eventName.type; - } - - //ensure we are using a real pixi event - if (!data || data.__isEventObject !== true) - { - data = new EventData(this, eventName, data); - } - - //iterate the listeners - var listeners = this._listeners[eventName].slice(0), - length = listeners.length, - fn = listeners[0], - i; - - for (i = 0; i < length; fn = listeners[++i]) - { - //call the event listener - fn.call(this, data); - - //if "stopImmediatePropagation" is called, stop calling sibling events - if (data.stoppedImmediate) - { - return this; - } - } - - //if "stopPropagation" is called then don't bubble the event - if (data.stopped) - { - return this; - } - - //bubble this event up the scene graph - if (this.parent && this.parent.emit) - { - this.parent.emit.call(this.parent, eventName, data); - } - - return this; - }; - - /** - * Register a new EventListener for the given event. - * - * @alias addEventListener - * @param eventName {string} Name of the event. - * @param callback {Functon} fn Callback function. - */ - obj.on = obj.addEventListener = function on(eventName, fn) - { - this._listeners = this._listeners || {}; - - (this._listeners[eventName] = this._listeners[eventName] || []) - .push(fn); - - return this; - }; - - /** - * Add an EventListener that's only called once. - * - * @param eventName {string} Name of the event. - * @param callback {Function} Callback function. - */ - obj.once = function once(eventName, fn) - { - this._listeners = this._listeners || {}; - - var self = this; - function onceHandlerWrapper() - { - fn.apply(self.off(eventName, onceHandlerWrapper), arguments); - } - onceHandlerWrapper._originalHandler = fn; - - return this.on(eventName, onceHandlerWrapper); - }; - - /** - * Remove event listeners. - * - * @alias removeEventListener - * @param eventName {string} The event we want to remove. - * @param callback {Function} The listener that we need to find. - */ - obj.off = obj.removeEventListener = function off(eventName, fn) - { - this._listeners = this._listeners || {}; - - if (!this._listeners[eventName]) - { - return this; - } - - var list = this._listeners[eventName], - i = fn ? list.length : 0; - - while(i-- > 0) - { - if (list[i] === fn || list[i]._originalHandler === fn) - { - list.splice(i, 1); - } - } - - if (list.length === 0) - { - delete this._listeners[eventName]; - } - - return this; - }; - - /** - * Remove all listeners or only the listeners for the specified event. - * - * @param eventName {string} The event you want to remove all listeners for. - */ - obj.removeAllListeners = function removeAllListeners(eventName) - { - this._listeners = this._listeners || {}; - - if (!this._listeners[eventName]) - { - return this; - } - - delete this._listeners[eventName]; - - return this; - }; -} - -module.exports = { - /** - * Mixes in the properties of the eventTarget prototype onto another object - * - * @param object {object} The obj to mix into - */ - mixin: function mixin(obj) - { - eventTarget(obj); - } -}; diff --git a/src/core/index.js b/src/core/index.js index 1d0a398..4fc777d 100644 --- a/src/core/index.js +++ b/src/core/index.js @@ -24,6 +24,7 @@ Sprite: require('./sprites/Sprite'), SpriteBatch: require('./sprites/SpriteBatch'), SpriteRenderer: require('./sprites/webgl/SpriteRenderer'), + SpriteBatchRenderer: require('./sprites/webgl/SpriteBatchRenderer'), // primitives Graphics: require('./graphics/Graphics'), @@ -43,6 +44,7 @@ // renderers - webgl WebGLRenderer: require('./renderers/webgl/WebGLRenderer'), + WebGLShaderManager: require('./renderers/webgl/managers/WebGLShaderManager'), Shader: require('./renderers/webgl/shaders/Shader'), /** diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js index 4e82baa..13892a6 100644 --- a/src/core/renderers/webgl/WebGLRenderer.js +++ b/src/core/renderers/webgl/WebGLRenderer.js @@ -1,5 +1,4 @@ -var WebGLFastSpriteBatch = require('./utils/WebGLFastSpriteBatch'), - WebGLShaderManager = require('./managers/WebGLShaderManager'), +var WebGLShaderManager = require('./managers/WebGLShaderManager'), WebGLMaskManager = require('./managers/WebGLMaskManager'), WebGLFilterManager = require('./managers/WebGLFilterManager'), WebGLBlendModeManager = require('./managers/WebGLBlendModeManager'), @@ -184,12 +183,6 @@ this.shaderManager = new WebGLShaderManager(this); /** - * Manages the rendering of sprites - * @member {WebGLFastSpriteBatch} - */ - this.fastSpriteBatch = new WebGLFastSpriteBatch(this); - - /** * Manages the masks using the stencil buffer * @member {WebGLMaskManager} */ diff --git a/src/core/renderers/webgl/shaders/FastShader.js b/src/core/renderers/webgl/shaders/FastShader.js deleted file mode 100644 index c80d040..0000000 --- a/src/core/renderers/webgl/shaders/FastShader.js +++ /dev/null @@ -1,75 +0,0 @@ -var Shader = require('./Shader'), - WebGLShaderManager = require('../managers/WebGLShaderManager'); - -/** - * @class - * @extends Shader - * @namespace PIXI - * @param shaderManager {WebGLShaderManager} The webgl shader manager this shader works for. - */ -function FastShader(shaderManager) -{ - Shader.call(this, - shaderManager, - // vertex shader - [ - 'attribute vec2 aVertexPosition;', - 'attribute vec2 aTextureCoord;', - 'attribute float aColor;', - - 'attribute vec2 aPositionCoord;', - 'attribute vec2 aScale;', - 'attribute float aRotation;', - - 'uniform vec2 projectionVector;', - 'uniform vec2 offsetVector;', - 'uniform mat3 uMatrix;', - - 'varying vec2 vTextureCoord;', - 'varying float vColor;', - - 'const vec2 center = vec2(-1.0, 1.0);', - - 'void main(void){', - ' vec2 v;', - ' vec2 sv = aVertexPosition * aScale;', - ' v.x = (sv.x) * cos(aRotation) - (sv.y) * sin(aRotation);', - ' v.y = (sv.x) * sin(aRotation) + (sv.y) * cos(aRotation);', - ' v = ( uMatrix * vec3(v + aPositionCoord , 1.0) ).xy ;', - ' gl_Position = vec4( ( v / projectionVector) + center , 0.0, 1.0);', - ' vTextureCoord = aTextureCoord;', - // ' vec3 color = mod(vec3(aColor.y/65536.0, aColor.y/256.0, aColor.y), 256.0) / 256.0;', - ' vColor = aColor;', - '}' - ].join('\n'), - // fragment shader, use default - [ - 'precision lowp float;', - - 'varying vec2 vTextureCoord;', - 'varying float vColor;', - - 'uniform sampler2D uSampler;', - - 'void main(void){', - ' gl_FragColor = texture2D(uSampler, vTextureCoord) * vColor ;', - '}' - ].join('\n'), - // custom uniforms - { - uMatrix: { type: 'mat3', value: new Float32Array(9) } - }, - // custom attributes - { - aPositionCoord: 0, - aRotation: 0, - aScale: 0 - } - ); -} - -FastShader.prototype = Object.create(Shader.prototype); -FastShader.prototype.constructor = FastShader; -module.exports = FastShader; - -WebGLShaderManager.registerPlugin('fastShader', FastShader); diff --git a/src/core/renderers/webgl/shaders/Shader.js b/src/core/renderers/webgl/shaders/Shader.js index c60c5f9..84f321f 100644 --- a/src/core/renderers/webgl/shaders/Shader.js +++ b/src/core/renderers/webgl/shaders/Shader.js @@ -47,7 +47,9 @@ } this.attributes = { - aVertexPosition: 0 + aVertexPosition: 0, + aTextureCoord: 0, + aColor: 0 }; for (var a in customAttributes) @@ -67,7 +69,7 @@ 'attribute vec4 aColor;', 'uniform mat3 projectionMatrix;', - 'uniform vec2 projectionVector;', + // 'uniform vec2 projectionVector;', 'uniform vec2 offsetVector;', 'varying vec2 vTextureCoord;', diff --git a/src/core/renderers/webgl/utils/ObjectRenderer.js b/src/core/renderers/webgl/utils/ObjectRenderer.js index 3b5f432..a07a9b7 100644 --- a/src/core/renderers/webgl/utils/ObjectRenderer.js +++ b/src/core/renderers/webgl/utils/ObjectRenderer.js @@ -25,7 +25,7 @@ ObjectRenderer.prototype.stop = function () { - // flush! + this.flush(); }; ObjectRenderer.prototype.flush = function () diff --git a/src/core/renderers/webgl/utils/WebGLFastSpriteBatch.js b/src/core/renderers/webgl/utils/WebGLFastSpriteBatch.js deleted file mode 100644 index 3f37b7d..0000000 --- a/src/core/renderers/webgl/utils/WebGLFastSpriteBatch.js +++ /dev/null @@ -1,466 +0,0 @@ -/** - * @author Mat Groves - * - * Big thanks to the very clever Matt DesLauriers 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 - */ - -/** - * @class - * @private - * @namespace PIXI - * @param renderer {WebGLRenderer} The renderer this sprite batch works for. - */ -function WebGLFastSpriteBatch(renderer) -{ - /** - * The renderer instance this sprite batch operates on. - * - * @member {WebGLRenderer} - */ - this.renderer = renderer; - - /** - * - * - * @member {number} - */ - this.vertSize = 10; - - /** - * - * - * @member {number} - */ - this.vertByteSize = this.vertSize * 4; - - /** - * - * - * @member {number} - */ - this.maxSize = 6000;//Math.pow(2, 16) / this.vertSize; - - /** - * - * - * @member {number} - */ - this.size = this.maxSize; - - //the total number of floats in our batch - var numVerts = this.size * this.vertByteSize; - - //the total number of indices in our batch - var numIndices = this.maxSize * 6; - - /** - * Vertex data - * - * @member {Float32Array} - */ - this.vertices = new Float32Array(numVerts); - - /** - * Index data - * - * @member {Uint16Array} - */ - this.indices = new Uint16Array(numIndices); - - /** - * - * - * @member {object} - */ - this.vertexBuffer = null; - - /** - * - * - * @member {object} - */ - this.indexBuffer = null; - - /** - * - * - * @member {number} - */ - 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; - } - - /** - * - * - * @member {boolean} - */ - this.drawing = false; - - /** - * - * - * @member {number} - */ - this.currentBatchSize = 0; - - /** - * - * - * @member {BaseTexture} - */ - this.currentBaseTexture = null; - - /** - * - * - * @member {number} - */ - this.currentBlendMode = 0; - - /** - * - * - * @member {object} - */ - this.shader = null; - - /** - * - * - * @member {Matrix} - */ - this.matrix = null; - - // listen for context and update necessary buffers - var self = this; - this.renderer.on('context', function () - { - self.setupContext(); - }); -} - -WebGLFastSpriteBatch.prototype.constructor = WebGLFastSpriteBatch; -module.exports = WebGLFastSpriteBatch; - -/** - * Sets the WebGL Context. - * - * @param gl {WebGLContext} the current WebGL drawing context - */ -WebGLFastSpriteBatch.prototype.setupContext = function () -{ - var gl = this.renderer.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); -}; - -/** - * @param spriteBatch {SpriteBatch} The SpriteBatch container to prepare for. - */ -WebGLFastSpriteBatch.prototype.begin = function (spriteBatch) -{ - this.shader = this.renderer.shaderManager.plugins.fastShader; - - this.matrix = spriteBatch.worldTransform.toArray(true); - - this.start(); -}; - -/** - */ -WebGLFastSpriteBatch.prototype.end = function () -{ - this.flush(); -}; - -/** - * @param spriteBatch {SpriteBatch} The SpriteBatch container to render. - */ -WebGLFastSpriteBatch.prototype.render = function (spriteBatch) -{ - var children = spriteBatch.children; - var sprite = children[0]; - - // if the uvs have not updated then no point rendering just yet! - - // check texture. - if (!sprite.texture._uvs) - { - return; - } - - this.currentBaseTexture = sprite.texture.baseTexture; - - // check blend mode - if (sprite.blendMode !== this.renderer.blendModeManager.currentBlendMode) - { - this.flush(); - this.renderer.blendModeManager.setBlendMode(sprite.blendMode); - } - - for (var i=0,j= children.length; i= this.size) - { - this.flush(); - } -}; - -/** - * - */ -WebGLFastSpriteBatch.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.renderer.gl; - - // bind the current texture - if (!this.currentBaseTexture._glTextures[gl.id]) - { - this.renderer.updateTexture(this.currentBaseTexture, gl); - } - //TODO-SHOUD THIS BE ELSE??!?!?! - else - { - gl.bindTexture(gl.TEXTURE_2D, this.currentBaseTexture._glTextures[gl.id]); - } - - // upload the verts to the buffer - - if (this.currentBatchSize > ( this.size * 0.5 ) ) - { - gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.vertices); - } - else - { - var view = this.vertices.subarray(0, this.currentBatchSize * this.vertByteSize); - - 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.renderer.drawCount++; -}; - - -/** - * Ends the batch and flushes - * - */ -WebGLFastSpriteBatch.prototype.stop = function () -{ - this.flush(); -}; - -/** - * - */ -WebGLFastSpriteBatch.prototype.start = function () -{ - var gl = this.renderer.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.renderer.projection; - gl.uniform2f(this.shader.uniforms.projectionVector._location, projection.x, projection.y); - - // set the matrix - gl.uniformMatrix3fv(this.shader.uniforms.uMatrix._location, false, this.matrix); - - // set the pointers - var stride = this.vertByteSize; - - gl.vertexAttribPointer(this.shader.attributes.aVertexPosition, 2, gl.FLOAT, false, stride, 0); - gl.vertexAttribPointer(this.shader.attributes.aPositionCoord, 2, gl.FLOAT, false, stride, 2 * 4); - gl.vertexAttribPointer(this.shader.attributes.aScale, 2, gl.FLOAT, false, stride, 4 * 4); - gl.vertexAttribPointer(this.shader.attributes.aRotation, 1, gl.FLOAT, false, stride, 6 * 4); - gl.vertexAttribPointer(this.shader.attributes.aTextureCoord, 2, gl.FLOAT, false, stride, 7 * 4); - gl.vertexAttribPointer(this.shader.attributes.aColor, 1, gl.FLOAT, false, stride, 9 * 4); -}; diff --git a/src/core/sprites/SpriteBatch.js b/src/core/sprites/SpriteBatch.js index 4fe33e4..c1e674c 100644 --- a/src/core/sprites/SpriteBatch.js +++ b/src/core/sprites/SpriteBatch.js @@ -59,14 +59,23 @@ return; } - renderer.spriteBatch.stop(); + // renderer.spriteBatch.stop(); - renderer.shaderManager.setShader(renderer.shaderManager.plugins.fastShader); + // renderer.shaderManager.setShader(renderer.shaderManager.plugins.fastShader); - renderer.fastSpriteBatch.begin(this); - renderer.fastSpriteBatch.render(this); + // renderer.fastSpriteBatch.begin(this); + // renderer.fastSpriteBatch.render(this); - renderer.spriteBatch.start(); + // renderer.spriteBatch.start(); + + renderer.currentRenderer.stop(); + + renderer.shaderManager.setShader(renderer.plugins.spriteBatch.shader); + + renderer.plugins.spriteBatch.start(this); + renderer.plugins.spriteBatch.render(this); + + renderer.currentRenderer.start(); }; /** diff --git a/src/core/sprites/webgl/SpriteBatchRenderer.js b/src/core/sprites/webgl/SpriteBatchRenderer.js new file mode 100644 index 0000000..82a2318 --- /dev/null +++ b/src/core/sprites/webgl/SpriteBatchRenderer.js @@ -0,0 +1,468 @@ +var ObjectRenderer = require('../../renderers/webgl/utils/ObjectRenderer'), + Shader = require('../../renderers/webgl/shaders/Shader'), + WebGLRenderer = require('../../renderers/webgl/WebGLRenderer'), + SpriteBatchShader = require('./SpriteBatchShader'); + +/** + * @author Mat Groves + * + * Big thanks to the very clever Matt DesLauriers 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 + */ + +/** + * @class + * @private + * @namespace PIXI + * @param renderer {WebGLRenderer} The renderer this sprite batch works for. + */ +function SpriteBatchRenderer(renderer) +{ + ObjectRenderer.call(this, renderer); + + /** + * + * + * @member {number} + */ + this.vertSize = 10; + + /** + * + * + * @member {number} + */ + this.vertByteSize = this.vertSize * 4; + + /** + * + * + * @member {number} + */ + this.maxSize = 6000;//Math.pow(2, 16) / this.vertSize; + + /** + * + * + * @member {number} + */ + this.size = this.maxSize; + + //the total number of floats in our batch + var numVerts = this.size * this.vertByteSize; + + //the total number of indices in our batch + var numIndices = this.maxSize * 6; + + /** + * Vertex data + * + * @member {Float32Array} + */ + this.vertices = new Float32Array(numVerts); + + /** + * Index data + * + * @member {Uint16Array} + */ + this.indices = new Uint16Array(numIndices); + + /** + * + * + * @member {object} + */ + this.vertexBuffer = null; + + /** + * + * + * @member {object} + */ + this.indexBuffer = null; + + /** + * + * + * @member {number} + */ + 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; + } + + /** + * + * + * @member {boolean} + */ + this.drawing = false; + + /** + * + * + * @member {number} + */ + this.currentBatchSize = 0; + + /** + * + * + * @member {BaseTexture} + */ + this.currentBaseTexture = null; + + /** + * + * + * @member {number} + */ + this.currentBlendMode = 0; + + /** + * + * + * @member {object} + */ + this.shader = null; + + this.setupContext(); + + // handle when the renderer's context changes. + this.renderer.on('context', this.setupContext.bind(this)); +} + +SpriteBatchRenderer.prototype = Object.create(ObjectRenderer.prototype); +SpriteBatchRenderer.prototype.constructor = SpriteBatchRenderer; +module.exports = SpriteBatchRenderer; + +WebGLRenderer.registerPlugin('spriteBatch', SpriteBatchRenderer); + +/** + * Sets the WebGL Context. + * + * @param gl {WebGLContext} the current WebGL drawing context + */ +SpriteBatchRenderer.prototype.setupContext = function () +{ + var gl = this.renderer.gl; + + // create a couple of buffers + this.vertexBuffer = gl.createBuffer(); + this.indexBuffer = gl.createBuffer(); + + this.shader = new SpriteBatchShader(this.renderer.shaderManager); + + // 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); +}; + +/** + */ +// SpriteBatchRenderer.prototype.stop = function () +// { +// this.flush(); +// }; + +/** + * @param spriteBatch {SpriteBatch} The SpriteBatch container to render. + */ +SpriteBatchRenderer.prototype.render = function (spriteBatch) +{ + var children = spriteBatch.children; + var sprite = children[0]; + + // if the uvs have not updated then no point rendering just yet! + + // check texture. + if (!sprite.texture._uvs) + { + return; + } + + this.currentBaseTexture = sprite.texture.baseTexture; + + // check blend mode + if (sprite.blendMode !== this.renderer.blendModeManager.currentBlendMode) + { + this.flush(); + this.renderer.blendModeManager.setBlendMode(sprite.blendMode); + } + + for (var i=0,j= children.length; i= this.size) + { + this.flush(); + } +}; + +/** + * + */ +SpriteBatchRenderer.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.renderer.gl; + + // bind the current texture + if (!this.currentBaseTexture._glTextures[gl.id]) + { + this.renderer.updateTexture(this.currentBaseTexture, gl); + } + //TODO-SHOUD THIS BE ELSE??!?!?! + else + { + gl.bindTexture(gl.TEXTURE_2D, this.currentBaseTexture._glTextures[gl.id]); + } + + // upload the verts to the buffer + + if (this.currentBatchSize > ( this.size * 0.5 ) ) + { + gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.vertices); + } + else + { + var view = this.vertices.subarray(0, this.currentBatchSize * this.vertByteSize); + + 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.renderer.drawCount++; +}; + +/** + * + */ +SpriteBatchRenderer.prototype.start = function (spriteBatch) +{ + var gl = this.renderer.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.renderer.projection; + // gl.uniform2f(this.shader.uniforms.projectionVector._location, projection.x, projection.y); + gl.uniformMatrix3fv(this.shader.uniforms.projectionMatrix._location, false, this.renderer.currentRenderTarget.projectionMatrix.toArray(true)); + + // set the matrix from the spriteBatch + gl.uniformMatrix3fv(this.shader.uniforms.uMatrix._location, false, spriteBatch.worldTransform.toArray(true)); + + // set the pointers + var stride = this.vertByteSize; + + gl.vertexAttribPointer(this.shader.attributes.aVertexPosition, 2, gl.FLOAT, false, stride, 0); + gl.vertexAttribPointer(this.shader.attributes.aTextureCoord, 2, gl.FLOAT, false, stride, 2 * 4); + gl.vertexAttribPointer(this.shader.attributes.aColor, 1, gl.FLOAT, false, stride, 4 * 4); + + gl.vertexAttribPointer(this.shader.attributes.aPositionCoord, 2, gl.FLOAT, false, stride, 5 * 4); + gl.vertexAttribPointer(this.shader.attributes.aScale, 2, gl.FLOAT, false, stride, 7 * 4); + gl.vertexAttribPointer(this.shader.attributes.aRotation, 1, gl.FLOAT, false, stride, 9 * 4); +}; + +/** + * Destroys the SpriteBatch. + * + */ +SpriteBatchRenderer.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.currentBaseTexture = null; + + this.drawing = false; + + this.shader = null; +}; diff --git a/src/core/sprites/webgl/SpriteBatchShader.js b/src/core/sprites/webgl/SpriteBatchShader.js new file mode 100644 index 0000000..1f53252 --- /dev/null +++ b/src/core/sprites/webgl/SpriteBatchShader.js @@ -0,0 +1,78 @@ +var Shader = require('../../renderers/webgl/shaders/Shader'); + +/** + * @class + * @extends Shader + * @namespace PIXI + * @param shaderManager {WebGLShaderManager} The webgl shader manager this shader works for. + */ +function SpriteBatchShader(shaderManager) +{ + Shader.call(this, + shaderManager, + // vertex shader + [ + 'attribute vec2 aVertexPosition;', + 'attribute vec2 aTextureCoord;', + 'attribute float aColor;', + + 'attribute vec2 aPositionCoord;', + 'attribute vec2 aScale;', + 'attribute float aRotation;', + + 'uniform mat3 projectionMatrix;', + // 'uniform vec2 projectionVector;', + // 'uniform vec2 offsetVector;', + 'uniform mat3 uMatrix;', + + 'varying vec2 vTextureCoord;', + 'varying float vColor;', + + // 'const vec2 center = vec2(-1.0, 1.0);', + + 'void main(void){', + ' vec2 v;', + ' vec2 sv = aVertexPosition * aScale;', + ' v.x = (sv.x) * cos(aRotation) - (sv.y) * sin(aRotation);', + ' v.y = (sv.x) * sin(aRotation) + (sv.y) * cos(aRotation);', + ' v = ( uMatrix * vec3(v + aPositionCoord , 1.0) ).xy ;', + + + // ' gl_Position = vec4( ( v / projectionVector) + center , 0.0, 1.0);', + ' gl_Position = vec4((projectionMatrix * vec3(v, 1.0)).xy, 0.0, 1.0);', + + + ' vTextureCoord = aTextureCoord;', + // ' vec3 color = mod(vec3(aColor.y/65536.0, aColor.y/256.0, aColor.y), 256.0) / 256.0;', + ' vColor = aColor;', + '}' + ].join('\n'), + // fragment shader, use default + [ + 'precision lowp float;', + + 'varying vec2 vTextureCoord;', + 'varying float vColor;', + + 'uniform sampler2D uSampler;', + + 'void main(void){', + ' gl_FragColor = texture2D(uSampler, vTextureCoord) * vColor ;', + '}' + ].join('\n'), + // custom uniforms + { + uMatrix: { type: 'mat3', value: new Float32Array(9) } + }, + // custom attributes + { + aPositionCoord: 0, + aScale: 0, + aRotation: 0 + } + ); +} + +SpriteBatchShader.prototype = Object.create(Shader.prototype); +SpriteBatchShader.prototype.constructor = SpriteBatchShader; +module.exports = SpriteBatchShader; diff --git a/src/core/sprites/webgl/SpriteRenderer.js b/src/core/sprites/webgl/SpriteRenderer.js index c006ba4..4f4eab4 100644 --- a/src/core/sprites/webgl/SpriteRenderer.js +++ b/src/core/sprites/webgl/SpriteRenderer.js @@ -28,13 +28,6 @@ /** * * - * @member {WebGLRenderer} - */ - this.renderer = renderer; - - /** - * - * * @member {number} */ this.vertSize = 5; @@ -127,13 +120,6 @@ /** * * - * @member {boolean} - */ - this.dirty = true; - - /** - * - * * @member {Array} */ this.textures = []; @@ -167,6 +153,9 @@ this.shader = null; this.setupContext(); + + // handle when the renderer's context changes. + this.renderer.on('context', this.setupContext.bind(this)); } SpriteRenderer.prototype = Object.create(ObjectRenderer.prototype); @@ -349,25 +338,6 @@ var gl = this.renderer.gl; var shader; - if (this.dirty) - { - this.dirty = false; - // 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); - - // this is the same for each shader? - var stride = this.vertByteSize; - gl.vertexAttribPointer(this.shader.attributes.aVertexPosition, 2, gl.FLOAT, false, stride, 0); - gl.vertexAttribPointer(this.shader.attributes.aTextureCoord, 2, gl.FLOAT, false, stride, 2 * 4); - - // color attributes will be interpreted as unsigned bytes and normalized - gl.vertexAttribPointer(this.shader.attributes.aColor, 4, gl.UNSIGNED_BYTE, true, stride, 4 * 4); - } - // upload the verts to the buffer if (this.currentBatchSize > ( this.size * 0.5 ) ) { @@ -487,22 +457,27 @@ }; /** - * Flushes the sprite renderer's current batch. - * - */ -SpriteRenderer.prototype.stop = function () -{ - this.flush(); - this.dirty = true; -}; - -/** * Starts a new sprite batch. * */ SpriteRenderer.prototype.start = function () { - this.dirty = true; + var gl = this.renderer.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); + + // this is the same for each shader? + var stride = this.vertByteSize; + gl.vertexAttribPointer(this.shader.attributes.aVertexPosition, 2, gl.FLOAT, false, stride, 0); + gl.vertexAttribPointer(this.shader.attributes.aTextureCoord, 2, gl.FLOAT, false, stride, 2 * 4); + + // color attributes will be interpreted as unsigned bytes and normalized + gl.vertexAttribPointer(this.shader.attributes.aColor, 4, gl.UNSIGNED_BYTE, true, stride, 4 * 4); }; /** @@ -514,16 +489,21 @@ this.renderer.gl.deleteBuffer(this.vertexBuffer); this.renderer.gl.deleteBuffer(this.indexBuffer); + this.shader.destroy(); + this.renderer = null; this.vertices = null; this.positions = null; this.colors = null; this.indices = null; + + this.vertexBuffer = null; + this.indexBuffer = null; + this.currentBaseTexture = null; this.drawing = false; - this.dirty = false; this.textures = null; this.blendModes = null; diff --git a/src/core/sprites/webgl/SpriteShader.js b/src/core/sprites/webgl/SpriteShader.js index 7d581ea..563ecdf 100644 --- a/src/core/sprites/webgl/SpriteShader.js +++ b/src/core/sprites/webgl/SpriteShader.js @@ -1,5 +1,4 @@ -var Shader = require('../../renderers/webgl/shaders/Shader'), - WebGLShaderManager = require('../../renderers/webgl/managers/WebGLShaderManager'); +var Shader = require('../../renderers/webgl/shaders/Shader'); /** * @class @@ -41,5 +40,3 @@ SpriteShader.prototype = Object.create(Shader.prototype); SpriteShader.prototype.constructor = SpriteShader; module.exports = SpriteShader; - -WebGLShaderManager.registerPlugin('spriteShader', SpriteShader); diff --git a/src/core/utils/EventTarget.js b/src/core/utils/EventTarget.js deleted file mode 100644 index 671a151..0000000 --- a/src/core/utils/EventTarget.js +++ /dev/null @@ -1,196 +0,0 @@ -var EventData = require('./EventData'); - -/** - * Mixins event emitter functionality to an object. - * - * @mixin - * @namespace PIXI - * @example - * function MyEmitter() {} - * - * eventTarget.mixin(MyEmitter.prototype); - * - * var em = new MyEmitter(); - * em.emit('eventName', 'some data', 'some more data', {}, null, ...); - */ -function eventTarget(obj) -{ - /** - * Return a list of assigned event listeners. - * - * @param eventName {string} The events that should be listed. - * @return {Array} An array of listener functions - */ - obj.listeners = function listeners(eventName) - { - this._listeners = this._listeners || {}; - - return this._listeners[eventName] ? this._listeners[eventName].slice() : []; - }; - - /** - * Emit an event to all registered event listeners. - * - * @alias dispatchEvent - * @param eventName {string} The name of the event. - * @return {boolean} Indication if we've emitted an event. - */ - obj.emit = obj.dispatchEvent = function emit(eventName, data) - { - this._listeners = this._listeners || {}; - - // fast return when there are no listeners - if (!this._listeners[eventName]) - { - return; - } - - //backwards compat with old method ".emit({ type: 'something' })" - if (typeof eventName === 'object') - { - data = eventName; - eventName = eventName.type; - } - - //ensure we are using a real pixi event - if (!data || data.__isEventObject !== true) - { - data = new EventData(this, eventName, data); - } - - //iterate the listeners - var listeners = this._listeners[eventName].slice(0), - length = listeners.length, - fn = listeners[0], - i; - - for (i = 0; i < length; fn = listeners[++i]) - { - //call the event listener - fn.call(this, data); - - //if "stopImmediatePropagation" is called, stop calling sibling events - if (data.stoppedImmediate) - { - return this; - } - } - - //if "stopPropagation" is called then don't bubble the event - if (data.stopped) - { - return this; - } - - //bubble this event up the scene graph - if (this.parent && this.parent.emit) - { - this.parent.emit.call(this.parent, eventName, data); - } - - return this; - }; - - /** - * Register a new EventListener for the given event. - * - * @alias addEventListener - * @param eventName {string} Name of the event. - * @param callback {Functon} fn Callback function. - */ - obj.on = obj.addEventListener = function on(eventName, fn) - { - this._listeners = this._listeners || {}; - - (this._listeners[eventName] = this._listeners[eventName] || []) - .push(fn); - - return this; - }; - - /** - * Add an EventListener that's only called once. - * - * @param eventName {string} Name of the event. - * @param callback {Function} Callback function. - */ - obj.once = function once(eventName, fn) - { - this._listeners = this._listeners || {}; - - var self = this; - function onceHandlerWrapper() - { - fn.apply(self.off(eventName, onceHandlerWrapper), arguments); - } - onceHandlerWrapper._originalHandler = fn; - - return this.on(eventName, onceHandlerWrapper); - }; - - /** - * Remove event listeners. - * - * @alias removeEventListener - * @param eventName {string} The event we want to remove. - * @param callback {Function} The listener that we need to find. - */ - obj.off = obj.removeEventListener = function off(eventName, fn) - { - this._listeners = this._listeners || {}; - - if (!this._listeners[eventName]) - { - return this; - } - - var list = this._listeners[eventName], - i = fn ? list.length : 0; - - while(i-- > 0) - { - if (list[i] === fn || list[i]._originalHandler === fn) - { - list.splice(i, 1); - } - } - - if (list.length === 0) - { - delete this._listeners[eventName]; - } - - return this; - }; - - /** - * Remove all listeners or only the listeners for the specified event. - * - * @param eventName {string} The event you want to remove all listeners for. - */ - obj.removeAllListeners = function removeAllListeners(eventName) - { - this._listeners = this._listeners || {}; - - if (!this._listeners[eventName]) - { - return this; - } - - delete this._listeners[eventName]; - - return this; - }; -} - -module.exports = { - /** - * Mixes in the properties of the eventTarget prototype onto another object - * - * @param object {object} The obj to mix into - */ - mixin: function mixin(obj) - { - eventTarget(obj); - } -}; diff --git a/src/core/utils/eventTarget.js b/src/core/utils/eventTarget.js new file mode 100644 index 0000000..b045b7d --- /dev/null +++ b/src/core/utils/eventTarget.js @@ -0,0 +1,196 @@ +var EventData = require('./EventData'); + +/** + * Mixins event emitter functionality to an object. + * + * @mixin + * @namespace PIXI + * @example + * function MyEmitter() {} + * + * eventTarget.mixin(MyEmitter.prototype); + * + * var em = new MyEmitter(); + * em.emit('eventName', 'some data', 'some more data', {}, null, ...); + */ +function eventTarget(obj) +{ + /** + * Return a list of assigned event listeners. + * + * @param eventName {string} The events that should be listed. + * @return {Array} An array of listener functions + */ + obj.listeners = function listeners(eventName) + { + this._listeners = this._listeners || {}; + + return this._listeners[eventName] ? this._listeners[eventName].slice() : []; + }; + + /** + * Emit an event to all registered event listeners. + * + * @alias dispatchEvent + * @param eventName {string} The name of the event. + * @return {boolean} Indication if we've emitted an event. + */ + obj.emit = obj.dispatchEvent = function emit(eventName, data) + { + this._listeners = this._listeners || {}; + + // fast return when there are no listeners + if (!this._listeners[eventName]) + { + return; + } + + //backwards compat with old method ".emit({ type: 'something' })" + if (typeof eventName === 'object') + { + data = eventName; + eventName = eventName.type; + } + + //ensure we are using a real pixi event + if (!data || data.__isEventObject !== true) + { + data = new EventData(this, eventName, data); + } + + //iterate the listeners + var listeners = this._listeners[eventName].slice(0), + length = listeners.length, + fn = listeners[0], + i; + + for (i = 0; i < length; fn = listeners[++i]) + { + //call the event listener + fn.call(this, data); + + //if "stopImmediatePropagation" is called, stop calling sibling events + if (data.stoppedImmediate) + { + return this; + } + } + + //if "stopPropagation" is called then don't bubble the event + if (data.stopped) + { + return this; + } + + //bubble this event up the scene graph + if (this.parent && this.parent.emit) + { + this.parent.emit.call(this.parent, eventName, data); + } + + return this; + }; + + /** + * Register a new EventListener for the given event. + * + * @alias addEventListener + * @param eventName {string} Name of the event. + * @param callback {Functon} fn Callback function. + */ + obj.on = obj.addEventListener = function on(eventName, fn) + { + this._listeners = this._listeners || {}; + + (this._listeners[eventName] = this._listeners[eventName] || []) + .push(fn); + + return this; + }; + + /** + * Add an EventListener that's only called once. + * + * @param eventName {string} Name of the event. + * @param callback {Function} Callback function. + */ + obj.once = function once(eventName, fn) + { + this._listeners = this._listeners || {}; + + var self = this; + function onceHandlerWrapper() + { + fn.apply(self.off(eventName, onceHandlerWrapper), arguments); + } + onceHandlerWrapper._originalHandler = fn; + + return this.on(eventName, onceHandlerWrapper); + }; + + /** + * Remove event listeners. + * + * @alias removeEventListener + * @param eventName {string} The event we want to remove. + * @param callback {Function} The listener that we need to find. + */ + obj.off = obj.removeEventListener = function off(eventName, fn) + { + this._listeners = this._listeners || {}; + + if (!this._listeners[eventName]) + { + return this; + } + + var list = this._listeners[eventName], + i = fn ? list.length : 0; + + while (i-- > 0) + { + if (list[i] === fn || list[i]._originalHandler === fn) + { + list.splice(i, 1); + } + } + + if (list.length === 0) + { + delete this._listeners[eventName]; + } + + return this; + }; + + /** + * Remove all listeners or only the listeners for the specified event. + * + * @param eventName {string} The event you want to remove all listeners for. + */ + obj.removeAllListeners = function removeAllListeners(eventName) + { + this._listeners = this._listeners || {}; + + if (!this._listeners[eventName]) + { + return this; + } + + delete this._listeners[eventName]; + + return this; + }; +} + +module.exports = { + /** + * Mixes in the properties of the eventTarget into another object + * + * @param object {object} The obj to mix into + */ + mixin: function mixin(obj) + { + eventTarget(obj); + } +}; diff --git a/src/core/index.js b/src/core/index.js index 1d0a398..4fc777d 100644 --- a/src/core/index.js +++ b/src/core/index.js @@ -24,6 +24,7 @@ Sprite: require('./sprites/Sprite'), SpriteBatch: require('./sprites/SpriteBatch'), SpriteRenderer: require('./sprites/webgl/SpriteRenderer'), + SpriteBatchRenderer: require('./sprites/webgl/SpriteBatchRenderer'), // primitives Graphics: require('./graphics/Graphics'), @@ -43,6 +44,7 @@ // renderers - webgl WebGLRenderer: require('./renderers/webgl/WebGLRenderer'), + WebGLShaderManager: require('./renderers/webgl/managers/WebGLShaderManager'), Shader: require('./renderers/webgl/shaders/Shader'), /** diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js index 4e82baa..13892a6 100644 --- a/src/core/renderers/webgl/WebGLRenderer.js +++ b/src/core/renderers/webgl/WebGLRenderer.js @@ -1,5 +1,4 @@ -var WebGLFastSpriteBatch = require('./utils/WebGLFastSpriteBatch'), - WebGLShaderManager = require('./managers/WebGLShaderManager'), +var WebGLShaderManager = require('./managers/WebGLShaderManager'), WebGLMaskManager = require('./managers/WebGLMaskManager'), WebGLFilterManager = require('./managers/WebGLFilterManager'), WebGLBlendModeManager = require('./managers/WebGLBlendModeManager'), @@ -184,12 +183,6 @@ this.shaderManager = new WebGLShaderManager(this); /** - * Manages the rendering of sprites - * @member {WebGLFastSpriteBatch} - */ - this.fastSpriteBatch = new WebGLFastSpriteBatch(this); - - /** * Manages the masks using the stencil buffer * @member {WebGLMaskManager} */ diff --git a/src/core/renderers/webgl/shaders/FastShader.js b/src/core/renderers/webgl/shaders/FastShader.js deleted file mode 100644 index c80d040..0000000 --- a/src/core/renderers/webgl/shaders/FastShader.js +++ /dev/null @@ -1,75 +0,0 @@ -var Shader = require('./Shader'), - WebGLShaderManager = require('../managers/WebGLShaderManager'); - -/** - * @class - * @extends Shader - * @namespace PIXI - * @param shaderManager {WebGLShaderManager} The webgl shader manager this shader works for. - */ -function FastShader(shaderManager) -{ - Shader.call(this, - shaderManager, - // vertex shader - [ - 'attribute vec2 aVertexPosition;', - 'attribute vec2 aTextureCoord;', - 'attribute float aColor;', - - 'attribute vec2 aPositionCoord;', - 'attribute vec2 aScale;', - 'attribute float aRotation;', - - 'uniform vec2 projectionVector;', - 'uniform vec2 offsetVector;', - 'uniform mat3 uMatrix;', - - 'varying vec2 vTextureCoord;', - 'varying float vColor;', - - 'const vec2 center = vec2(-1.0, 1.0);', - - 'void main(void){', - ' vec2 v;', - ' vec2 sv = aVertexPosition * aScale;', - ' v.x = (sv.x) * cos(aRotation) - (sv.y) * sin(aRotation);', - ' v.y = (sv.x) * sin(aRotation) + (sv.y) * cos(aRotation);', - ' v = ( uMatrix * vec3(v + aPositionCoord , 1.0) ).xy ;', - ' gl_Position = vec4( ( v / projectionVector) + center , 0.0, 1.0);', - ' vTextureCoord = aTextureCoord;', - // ' vec3 color = mod(vec3(aColor.y/65536.0, aColor.y/256.0, aColor.y), 256.0) / 256.0;', - ' vColor = aColor;', - '}' - ].join('\n'), - // fragment shader, use default - [ - 'precision lowp float;', - - 'varying vec2 vTextureCoord;', - 'varying float vColor;', - - 'uniform sampler2D uSampler;', - - 'void main(void){', - ' gl_FragColor = texture2D(uSampler, vTextureCoord) * vColor ;', - '}' - ].join('\n'), - // custom uniforms - { - uMatrix: { type: 'mat3', value: new Float32Array(9) } - }, - // custom attributes - { - aPositionCoord: 0, - aRotation: 0, - aScale: 0 - } - ); -} - -FastShader.prototype = Object.create(Shader.prototype); -FastShader.prototype.constructor = FastShader; -module.exports = FastShader; - -WebGLShaderManager.registerPlugin('fastShader', FastShader); diff --git a/src/core/renderers/webgl/shaders/Shader.js b/src/core/renderers/webgl/shaders/Shader.js index c60c5f9..84f321f 100644 --- a/src/core/renderers/webgl/shaders/Shader.js +++ b/src/core/renderers/webgl/shaders/Shader.js @@ -47,7 +47,9 @@ } this.attributes = { - aVertexPosition: 0 + aVertexPosition: 0, + aTextureCoord: 0, + aColor: 0 }; for (var a in customAttributes) @@ -67,7 +69,7 @@ 'attribute vec4 aColor;', 'uniform mat3 projectionMatrix;', - 'uniform vec2 projectionVector;', + // 'uniform vec2 projectionVector;', 'uniform vec2 offsetVector;', 'varying vec2 vTextureCoord;', diff --git a/src/core/renderers/webgl/utils/ObjectRenderer.js b/src/core/renderers/webgl/utils/ObjectRenderer.js index 3b5f432..a07a9b7 100644 --- a/src/core/renderers/webgl/utils/ObjectRenderer.js +++ b/src/core/renderers/webgl/utils/ObjectRenderer.js @@ -25,7 +25,7 @@ ObjectRenderer.prototype.stop = function () { - // flush! + this.flush(); }; ObjectRenderer.prototype.flush = function () diff --git a/src/core/renderers/webgl/utils/WebGLFastSpriteBatch.js b/src/core/renderers/webgl/utils/WebGLFastSpriteBatch.js deleted file mode 100644 index 3f37b7d..0000000 --- a/src/core/renderers/webgl/utils/WebGLFastSpriteBatch.js +++ /dev/null @@ -1,466 +0,0 @@ -/** - * @author Mat Groves - * - * Big thanks to the very clever Matt DesLauriers 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 - */ - -/** - * @class - * @private - * @namespace PIXI - * @param renderer {WebGLRenderer} The renderer this sprite batch works for. - */ -function WebGLFastSpriteBatch(renderer) -{ - /** - * The renderer instance this sprite batch operates on. - * - * @member {WebGLRenderer} - */ - this.renderer = renderer; - - /** - * - * - * @member {number} - */ - this.vertSize = 10; - - /** - * - * - * @member {number} - */ - this.vertByteSize = this.vertSize * 4; - - /** - * - * - * @member {number} - */ - this.maxSize = 6000;//Math.pow(2, 16) / this.vertSize; - - /** - * - * - * @member {number} - */ - this.size = this.maxSize; - - //the total number of floats in our batch - var numVerts = this.size * this.vertByteSize; - - //the total number of indices in our batch - var numIndices = this.maxSize * 6; - - /** - * Vertex data - * - * @member {Float32Array} - */ - this.vertices = new Float32Array(numVerts); - - /** - * Index data - * - * @member {Uint16Array} - */ - this.indices = new Uint16Array(numIndices); - - /** - * - * - * @member {object} - */ - this.vertexBuffer = null; - - /** - * - * - * @member {object} - */ - this.indexBuffer = null; - - /** - * - * - * @member {number} - */ - 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; - } - - /** - * - * - * @member {boolean} - */ - this.drawing = false; - - /** - * - * - * @member {number} - */ - this.currentBatchSize = 0; - - /** - * - * - * @member {BaseTexture} - */ - this.currentBaseTexture = null; - - /** - * - * - * @member {number} - */ - this.currentBlendMode = 0; - - /** - * - * - * @member {object} - */ - this.shader = null; - - /** - * - * - * @member {Matrix} - */ - this.matrix = null; - - // listen for context and update necessary buffers - var self = this; - this.renderer.on('context', function () - { - self.setupContext(); - }); -} - -WebGLFastSpriteBatch.prototype.constructor = WebGLFastSpriteBatch; -module.exports = WebGLFastSpriteBatch; - -/** - * Sets the WebGL Context. - * - * @param gl {WebGLContext} the current WebGL drawing context - */ -WebGLFastSpriteBatch.prototype.setupContext = function () -{ - var gl = this.renderer.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); -}; - -/** - * @param spriteBatch {SpriteBatch} The SpriteBatch container to prepare for. - */ -WebGLFastSpriteBatch.prototype.begin = function (spriteBatch) -{ - this.shader = this.renderer.shaderManager.plugins.fastShader; - - this.matrix = spriteBatch.worldTransform.toArray(true); - - this.start(); -}; - -/** - */ -WebGLFastSpriteBatch.prototype.end = function () -{ - this.flush(); -}; - -/** - * @param spriteBatch {SpriteBatch} The SpriteBatch container to render. - */ -WebGLFastSpriteBatch.prototype.render = function (spriteBatch) -{ - var children = spriteBatch.children; - var sprite = children[0]; - - // if the uvs have not updated then no point rendering just yet! - - // check texture. - if (!sprite.texture._uvs) - { - return; - } - - this.currentBaseTexture = sprite.texture.baseTexture; - - // check blend mode - if (sprite.blendMode !== this.renderer.blendModeManager.currentBlendMode) - { - this.flush(); - this.renderer.blendModeManager.setBlendMode(sprite.blendMode); - } - - for (var i=0,j= children.length; i= this.size) - { - this.flush(); - } -}; - -/** - * - */ -WebGLFastSpriteBatch.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.renderer.gl; - - // bind the current texture - if (!this.currentBaseTexture._glTextures[gl.id]) - { - this.renderer.updateTexture(this.currentBaseTexture, gl); - } - //TODO-SHOUD THIS BE ELSE??!?!?! - else - { - gl.bindTexture(gl.TEXTURE_2D, this.currentBaseTexture._glTextures[gl.id]); - } - - // upload the verts to the buffer - - if (this.currentBatchSize > ( this.size * 0.5 ) ) - { - gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.vertices); - } - else - { - var view = this.vertices.subarray(0, this.currentBatchSize * this.vertByteSize); - - 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.renderer.drawCount++; -}; - - -/** - * Ends the batch and flushes - * - */ -WebGLFastSpriteBatch.prototype.stop = function () -{ - this.flush(); -}; - -/** - * - */ -WebGLFastSpriteBatch.prototype.start = function () -{ - var gl = this.renderer.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.renderer.projection; - gl.uniform2f(this.shader.uniforms.projectionVector._location, projection.x, projection.y); - - // set the matrix - gl.uniformMatrix3fv(this.shader.uniforms.uMatrix._location, false, this.matrix); - - // set the pointers - var stride = this.vertByteSize; - - gl.vertexAttribPointer(this.shader.attributes.aVertexPosition, 2, gl.FLOAT, false, stride, 0); - gl.vertexAttribPointer(this.shader.attributes.aPositionCoord, 2, gl.FLOAT, false, stride, 2 * 4); - gl.vertexAttribPointer(this.shader.attributes.aScale, 2, gl.FLOAT, false, stride, 4 * 4); - gl.vertexAttribPointer(this.shader.attributes.aRotation, 1, gl.FLOAT, false, stride, 6 * 4); - gl.vertexAttribPointer(this.shader.attributes.aTextureCoord, 2, gl.FLOAT, false, stride, 7 * 4); - gl.vertexAttribPointer(this.shader.attributes.aColor, 1, gl.FLOAT, false, stride, 9 * 4); -}; diff --git a/src/core/sprites/SpriteBatch.js b/src/core/sprites/SpriteBatch.js index 4fe33e4..c1e674c 100644 --- a/src/core/sprites/SpriteBatch.js +++ b/src/core/sprites/SpriteBatch.js @@ -59,14 +59,23 @@ return; } - renderer.spriteBatch.stop(); + // renderer.spriteBatch.stop(); - renderer.shaderManager.setShader(renderer.shaderManager.plugins.fastShader); + // renderer.shaderManager.setShader(renderer.shaderManager.plugins.fastShader); - renderer.fastSpriteBatch.begin(this); - renderer.fastSpriteBatch.render(this); + // renderer.fastSpriteBatch.begin(this); + // renderer.fastSpriteBatch.render(this); - renderer.spriteBatch.start(); + // renderer.spriteBatch.start(); + + renderer.currentRenderer.stop(); + + renderer.shaderManager.setShader(renderer.plugins.spriteBatch.shader); + + renderer.plugins.spriteBatch.start(this); + renderer.plugins.spriteBatch.render(this); + + renderer.currentRenderer.start(); }; /** diff --git a/src/core/sprites/webgl/SpriteBatchRenderer.js b/src/core/sprites/webgl/SpriteBatchRenderer.js new file mode 100644 index 0000000..82a2318 --- /dev/null +++ b/src/core/sprites/webgl/SpriteBatchRenderer.js @@ -0,0 +1,468 @@ +var ObjectRenderer = require('../../renderers/webgl/utils/ObjectRenderer'), + Shader = require('../../renderers/webgl/shaders/Shader'), + WebGLRenderer = require('../../renderers/webgl/WebGLRenderer'), + SpriteBatchShader = require('./SpriteBatchShader'); + +/** + * @author Mat Groves + * + * Big thanks to the very clever Matt DesLauriers 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 + */ + +/** + * @class + * @private + * @namespace PIXI + * @param renderer {WebGLRenderer} The renderer this sprite batch works for. + */ +function SpriteBatchRenderer(renderer) +{ + ObjectRenderer.call(this, renderer); + + /** + * + * + * @member {number} + */ + this.vertSize = 10; + + /** + * + * + * @member {number} + */ + this.vertByteSize = this.vertSize * 4; + + /** + * + * + * @member {number} + */ + this.maxSize = 6000;//Math.pow(2, 16) / this.vertSize; + + /** + * + * + * @member {number} + */ + this.size = this.maxSize; + + //the total number of floats in our batch + var numVerts = this.size * this.vertByteSize; + + //the total number of indices in our batch + var numIndices = this.maxSize * 6; + + /** + * Vertex data + * + * @member {Float32Array} + */ + this.vertices = new Float32Array(numVerts); + + /** + * Index data + * + * @member {Uint16Array} + */ + this.indices = new Uint16Array(numIndices); + + /** + * + * + * @member {object} + */ + this.vertexBuffer = null; + + /** + * + * + * @member {object} + */ + this.indexBuffer = null; + + /** + * + * + * @member {number} + */ + 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; + } + + /** + * + * + * @member {boolean} + */ + this.drawing = false; + + /** + * + * + * @member {number} + */ + this.currentBatchSize = 0; + + /** + * + * + * @member {BaseTexture} + */ + this.currentBaseTexture = null; + + /** + * + * + * @member {number} + */ + this.currentBlendMode = 0; + + /** + * + * + * @member {object} + */ + this.shader = null; + + this.setupContext(); + + // handle when the renderer's context changes. + this.renderer.on('context', this.setupContext.bind(this)); +} + +SpriteBatchRenderer.prototype = Object.create(ObjectRenderer.prototype); +SpriteBatchRenderer.prototype.constructor = SpriteBatchRenderer; +module.exports = SpriteBatchRenderer; + +WebGLRenderer.registerPlugin('spriteBatch', SpriteBatchRenderer); + +/** + * Sets the WebGL Context. + * + * @param gl {WebGLContext} the current WebGL drawing context + */ +SpriteBatchRenderer.prototype.setupContext = function () +{ + var gl = this.renderer.gl; + + // create a couple of buffers + this.vertexBuffer = gl.createBuffer(); + this.indexBuffer = gl.createBuffer(); + + this.shader = new SpriteBatchShader(this.renderer.shaderManager); + + // 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); +}; + +/** + */ +// SpriteBatchRenderer.prototype.stop = function () +// { +// this.flush(); +// }; + +/** + * @param spriteBatch {SpriteBatch} The SpriteBatch container to render. + */ +SpriteBatchRenderer.prototype.render = function (spriteBatch) +{ + var children = spriteBatch.children; + var sprite = children[0]; + + // if the uvs have not updated then no point rendering just yet! + + // check texture. + if (!sprite.texture._uvs) + { + return; + } + + this.currentBaseTexture = sprite.texture.baseTexture; + + // check blend mode + if (sprite.blendMode !== this.renderer.blendModeManager.currentBlendMode) + { + this.flush(); + this.renderer.blendModeManager.setBlendMode(sprite.blendMode); + } + + for (var i=0,j= children.length; i= this.size) + { + this.flush(); + } +}; + +/** + * + */ +SpriteBatchRenderer.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.renderer.gl; + + // bind the current texture + if (!this.currentBaseTexture._glTextures[gl.id]) + { + this.renderer.updateTexture(this.currentBaseTexture, gl); + } + //TODO-SHOUD THIS BE ELSE??!?!?! + else + { + gl.bindTexture(gl.TEXTURE_2D, this.currentBaseTexture._glTextures[gl.id]); + } + + // upload the verts to the buffer + + if (this.currentBatchSize > ( this.size * 0.5 ) ) + { + gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.vertices); + } + else + { + var view = this.vertices.subarray(0, this.currentBatchSize * this.vertByteSize); + + 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.renderer.drawCount++; +}; + +/** + * + */ +SpriteBatchRenderer.prototype.start = function (spriteBatch) +{ + var gl = this.renderer.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.renderer.projection; + // gl.uniform2f(this.shader.uniforms.projectionVector._location, projection.x, projection.y); + gl.uniformMatrix3fv(this.shader.uniforms.projectionMatrix._location, false, this.renderer.currentRenderTarget.projectionMatrix.toArray(true)); + + // set the matrix from the spriteBatch + gl.uniformMatrix3fv(this.shader.uniforms.uMatrix._location, false, spriteBatch.worldTransform.toArray(true)); + + // set the pointers + var stride = this.vertByteSize; + + gl.vertexAttribPointer(this.shader.attributes.aVertexPosition, 2, gl.FLOAT, false, stride, 0); + gl.vertexAttribPointer(this.shader.attributes.aTextureCoord, 2, gl.FLOAT, false, stride, 2 * 4); + gl.vertexAttribPointer(this.shader.attributes.aColor, 1, gl.FLOAT, false, stride, 4 * 4); + + gl.vertexAttribPointer(this.shader.attributes.aPositionCoord, 2, gl.FLOAT, false, stride, 5 * 4); + gl.vertexAttribPointer(this.shader.attributes.aScale, 2, gl.FLOAT, false, stride, 7 * 4); + gl.vertexAttribPointer(this.shader.attributes.aRotation, 1, gl.FLOAT, false, stride, 9 * 4); +}; + +/** + * Destroys the SpriteBatch. + * + */ +SpriteBatchRenderer.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.currentBaseTexture = null; + + this.drawing = false; + + this.shader = null; +}; diff --git a/src/core/sprites/webgl/SpriteBatchShader.js b/src/core/sprites/webgl/SpriteBatchShader.js new file mode 100644 index 0000000..1f53252 --- /dev/null +++ b/src/core/sprites/webgl/SpriteBatchShader.js @@ -0,0 +1,78 @@ +var Shader = require('../../renderers/webgl/shaders/Shader'); + +/** + * @class + * @extends Shader + * @namespace PIXI + * @param shaderManager {WebGLShaderManager} The webgl shader manager this shader works for. + */ +function SpriteBatchShader(shaderManager) +{ + Shader.call(this, + shaderManager, + // vertex shader + [ + 'attribute vec2 aVertexPosition;', + 'attribute vec2 aTextureCoord;', + 'attribute float aColor;', + + 'attribute vec2 aPositionCoord;', + 'attribute vec2 aScale;', + 'attribute float aRotation;', + + 'uniform mat3 projectionMatrix;', + // 'uniform vec2 projectionVector;', + // 'uniform vec2 offsetVector;', + 'uniform mat3 uMatrix;', + + 'varying vec2 vTextureCoord;', + 'varying float vColor;', + + // 'const vec2 center = vec2(-1.0, 1.0);', + + 'void main(void){', + ' vec2 v;', + ' vec2 sv = aVertexPosition * aScale;', + ' v.x = (sv.x) * cos(aRotation) - (sv.y) * sin(aRotation);', + ' v.y = (sv.x) * sin(aRotation) + (sv.y) * cos(aRotation);', + ' v = ( uMatrix * vec3(v + aPositionCoord , 1.0) ).xy ;', + + + // ' gl_Position = vec4( ( v / projectionVector) + center , 0.0, 1.0);', + ' gl_Position = vec4((projectionMatrix * vec3(v, 1.0)).xy, 0.0, 1.0);', + + + ' vTextureCoord = aTextureCoord;', + // ' vec3 color = mod(vec3(aColor.y/65536.0, aColor.y/256.0, aColor.y), 256.0) / 256.0;', + ' vColor = aColor;', + '}' + ].join('\n'), + // fragment shader, use default + [ + 'precision lowp float;', + + 'varying vec2 vTextureCoord;', + 'varying float vColor;', + + 'uniform sampler2D uSampler;', + + 'void main(void){', + ' gl_FragColor = texture2D(uSampler, vTextureCoord) * vColor ;', + '}' + ].join('\n'), + // custom uniforms + { + uMatrix: { type: 'mat3', value: new Float32Array(9) } + }, + // custom attributes + { + aPositionCoord: 0, + aScale: 0, + aRotation: 0 + } + ); +} + +SpriteBatchShader.prototype = Object.create(Shader.prototype); +SpriteBatchShader.prototype.constructor = SpriteBatchShader; +module.exports = SpriteBatchShader; diff --git a/src/core/sprites/webgl/SpriteRenderer.js b/src/core/sprites/webgl/SpriteRenderer.js index c006ba4..4f4eab4 100644 --- a/src/core/sprites/webgl/SpriteRenderer.js +++ b/src/core/sprites/webgl/SpriteRenderer.js @@ -28,13 +28,6 @@ /** * * - * @member {WebGLRenderer} - */ - this.renderer = renderer; - - /** - * - * * @member {number} */ this.vertSize = 5; @@ -127,13 +120,6 @@ /** * * - * @member {boolean} - */ - this.dirty = true; - - /** - * - * * @member {Array} */ this.textures = []; @@ -167,6 +153,9 @@ this.shader = null; this.setupContext(); + + // handle when the renderer's context changes. + this.renderer.on('context', this.setupContext.bind(this)); } SpriteRenderer.prototype = Object.create(ObjectRenderer.prototype); @@ -349,25 +338,6 @@ var gl = this.renderer.gl; var shader; - if (this.dirty) - { - this.dirty = false; - // 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); - - // this is the same for each shader? - var stride = this.vertByteSize; - gl.vertexAttribPointer(this.shader.attributes.aVertexPosition, 2, gl.FLOAT, false, stride, 0); - gl.vertexAttribPointer(this.shader.attributes.aTextureCoord, 2, gl.FLOAT, false, stride, 2 * 4); - - // color attributes will be interpreted as unsigned bytes and normalized - gl.vertexAttribPointer(this.shader.attributes.aColor, 4, gl.UNSIGNED_BYTE, true, stride, 4 * 4); - } - // upload the verts to the buffer if (this.currentBatchSize > ( this.size * 0.5 ) ) { @@ -487,22 +457,27 @@ }; /** - * Flushes the sprite renderer's current batch. - * - */ -SpriteRenderer.prototype.stop = function () -{ - this.flush(); - this.dirty = true; -}; - -/** * Starts a new sprite batch. * */ SpriteRenderer.prototype.start = function () { - this.dirty = true; + var gl = this.renderer.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); + + // this is the same for each shader? + var stride = this.vertByteSize; + gl.vertexAttribPointer(this.shader.attributes.aVertexPosition, 2, gl.FLOAT, false, stride, 0); + gl.vertexAttribPointer(this.shader.attributes.aTextureCoord, 2, gl.FLOAT, false, stride, 2 * 4); + + // color attributes will be interpreted as unsigned bytes and normalized + gl.vertexAttribPointer(this.shader.attributes.aColor, 4, gl.UNSIGNED_BYTE, true, stride, 4 * 4); }; /** @@ -514,16 +489,21 @@ this.renderer.gl.deleteBuffer(this.vertexBuffer); this.renderer.gl.deleteBuffer(this.indexBuffer); + this.shader.destroy(); + this.renderer = null; this.vertices = null; this.positions = null; this.colors = null; this.indices = null; + + this.vertexBuffer = null; + this.indexBuffer = null; + this.currentBaseTexture = null; this.drawing = false; - this.dirty = false; this.textures = null; this.blendModes = null; diff --git a/src/core/sprites/webgl/SpriteShader.js b/src/core/sprites/webgl/SpriteShader.js index 7d581ea..563ecdf 100644 --- a/src/core/sprites/webgl/SpriteShader.js +++ b/src/core/sprites/webgl/SpriteShader.js @@ -1,5 +1,4 @@ -var Shader = require('../../renderers/webgl/shaders/Shader'), - WebGLShaderManager = require('../../renderers/webgl/managers/WebGLShaderManager'); +var Shader = require('../../renderers/webgl/shaders/Shader'); /** * @class @@ -41,5 +40,3 @@ SpriteShader.prototype = Object.create(Shader.prototype); SpriteShader.prototype.constructor = SpriteShader; module.exports = SpriteShader; - -WebGLShaderManager.registerPlugin('spriteShader', SpriteShader); diff --git a/src/core/utils/EventTarget.js b/src/core/utils/EventTarget.js deleted file mode 100644 index 671a151..0000000 --- a/src/core/utils/EventTarget.js +++ /dev/null @@ -1,196 +0,0 @@ -var EventData = require('./EventData'); - -/** - * Mixins event emitter functionality to an object. - * - * @mixin - * @namespace PIXI - * @example - * function MyEmitter() {} - * - * eventTarget.mixin(MyEmitter.prototype); - * - * var em = new MyEmitter(); - * em.emit('eventName', 'some data', 'some more data', {}, null, ...); - */ -function eventTarget(obj) -{ - /** - * Return a list of assigned event listeners. - * - * @param eventName {string} The events that should be listed. - * @return {Array} An array of listener functions - */ - obj.listeners = function listeners(eventName) - { - this._listeners = this._listeners || {}; - - return this._listeners[eventName] ? this._listeners[eventName].slice() : []; - }; - - /** - * Emit an event to all registered event listeners. - * - * @alias dispatchEvent - * @param eventName {string} The name of the event. - * @return {boolean} Indication if we've emitted an event. - */ - obj.emit = obj.dispatchEvent = function emit(eventName, data) - { - this._listeners = this._listeners || {}; - - // fast return when there are no listeners - if (!this._listeners[eventName]) - { - return; - } - - //backwards compat with old method ".emit({ type: 'something' })" - if (typeof eventName === 'object') - { - data = eventName; - eventName = eventName.type; - } - - //ensure we are using a real pixi event - if (!data || data.__isEventObject !== true) - { - data = new EventData(this, eventName, data); - } - - //iterate the listeners - var listeners = this._listeners[eventName].slice(0), - length = listeners.length, - fn = listeners[0], - i; - - for (i = 0; i < length; fn = listeners[++i]) - { - //call the event listener - fn.call(this, data); - - //if "stopImmediatePropagation" is called, stop calling sibling events - if (data.stoppedImmediate) - { - return this; - } - } - - //if "stopPropagation" is called then don't bubble the event - if (data.stopped) - { - return this; - } - - //bubble this event up the scene graph - if (this.parent && this.parent.emit) - { - this.parent.emit.call(this.parent, eventName, data); - } - - return this; - }; - - /** - * Register a new EventListener for the given event. - * - * @alias addEventListener - * @param eventName {string} Name of the event. - * @param callback {Functon} fn Callback function. - */ - obj.on = obj.addEventListener = function on(eventName, fn) - { - this._listeners = this._listeners || {}; - - (this._listeners[eventName] = this._listeners[eventName] || []) - .push(fn); - - return this; - }; - - /** - * Add an EventListener that's only called once. - * - * @param eventName {string} Name of the event. - * @param callback {Function} Callback function. - */ - obj.once = function once(eventName, fn) - { - this._listeners = this._listeners || {}; - - var self = this; - function onceHandlerWrapper() - { - fn.apply(self.off(eventName, onceHandlerWrapper), arguments); - } - onceHandlerWrapper._originalHandler = fn; - - return this.on(eventName, onceHandlerWrapper); - }; - - /** - * Remove event listeners. - * - * @alias removeEventListener - * @param eventName {string} The event we want to remove. - * @param callback {Function} The listener that we need to find. - */ - obj.off = obj.removeEventListener = function off(eventName, fn) - { - this._listeners = this._listeners || {}; - - if (!this._listeners[eventName]) - { - return this; - } - - var list = this._listeners[eventName], - i = fn ? list.length : 0; - - while(i-- > 0) - { - if (list[i] === fn || list[i]._originalHandler === fn) - { - list.splice(i, 1); - } - } - - if (list.length === 0) - { - delete this._listeners[eventName]; - } - - return this; - }; - - /** - * Remove all listeners or only the listeners for the specified event. - * - * @param eventName {string} The event you want to remove all listeners for. - */ - obj.removeAllListeners = function removeAllListeners(eventName) - { - this._listeners = this._listeners || {}; - - if (!this._listeners[eventName]) - { - return this; - } - - delete this._listeners[eventName]; - - return this; - }; -} - -module.exports = { - /** - * Mixes in the properties of the eventTarget prototype onto another object - * - * @param object {object} The obj to mix into - */ - mixin: function mixin(obj) - { - eventTarget(obj); - } -}; diff --git a/src/core/utils/eventTarget.js b/src/core/utils/eventTarget.js new file mode 100644 index 0000000..b045b7d --- /dev/null +++ b/src/core/utils/eventTarget.js @@ -0,0 +1,196 @@ +var EventData = require('./EventData'); + +/** + * Mixins event emitter functionality to an object. + * + * @mixin + * @namespace PIXI + * @example + * function MyEmitter() {} + * + * eventTarget.mixin(MyEmitter.prototype); + * + * var em = new MyEmitter(); + * em.emit('eventName', 'some data', 'some more data', {}, null, ...); + */ +function eventTarget(obj) +{ + /** + * Return a list of assigned event listeners. + * + * @param eventName {string} The events that should be listed. + * @return {Array} An array of listener functions + */ + obj.listeners = function listeners(eventName) + { + this._listeners = this._listeners || {}; + + return this._listeners[eventName] ? this._listeners[eventName].slice() : []; + }; + + /** + * Emit an event to all registered event listeners. + * + * @alias dispatchEvent + * @param eventName {string} The name of the event. + * @return {boolean} Indication if we've emitted an event. + */ + obj.emit = obj.dispatchEvent = function emit(eventName, data) + { + this._listeners = this._listeners || {}; + + // fast return when there are no listeners + if (!this._listeners[eventName]) + { + return; + } + + //backwards compat with old method ".emit({ type: 'something' })" + if (typeof eventName === 'object') + { + data = eventName; + eventName = eventName.type; + } + + //ensure we are using a real pixi event + if (!data || data.__isEventObject !== true) + { + data = new EventData(this, eventName, data); + } + + //iterate the listeners + var listeners = this._listeners[eventName].slice(0), + length = listeners.length, + fn = listeners[0], + i; + + for (i = 0; i < length; fn = listeners[++i]) + { + //call the event listener + fn.call(this, data); + + //if "stopImmediatePropagation" is called, stop calling sibling events + if (data.stoppedImmediate) + { + return this; + } + } + + //if "stopPropagation" is called then don't bubble the event + if (data.stopped) + { + return this; + } + + //bubble this event up the scene graph + if (this.parent && this.parent.emit) + { + this.parent.emit.call(this.parent, eventName, data); + } + + return this; + }; + + /** + * Register a new EventListener for the given event. + * + * @alias addEventListener + * @param eventName {string} Name of the event. + * @param callback {Functon} fn Callback function. + */ + obj.on = obj.addEventListener = function on(eventName, fn) + { + this._listeners = this._listeners || {}; + + (this._listeners[eventName] = this._listeners[eventName] || []) + .push(fn); + + return this; + }; + + /** + * Add an EventListener that's only called once. + * + * @param eventName {string} Name of the event. + * @param callback {Function} Callback function. + */ + obj.once = function once(eventName, fn) + { + this._listeners = this._listeners || {}; + + var self = this; + function onceHandlerWrapper() + { + fn.apply(self.off(eventName, onceHandlerWrapper), arguments); + } + onceHandlerWrapper._originalHandler = fn; + + return this.on(eventName, onceHandlerWrapper); + }; + + /** + * Remove event listeners. + * + * @alias removeEventListener + * @param eventName {string} The event we want to remove. + * @param callback {Function} The listener that we need to find. + */ + obj.off = obj.removeEventListener = function off(eventName, fn) + { + this._listeners = this._listeners || {}; + + if (!this._listeners[eventName]) + { + return this; + } + + var list = this._listeners[eventName], + i = fn ? list.length : 0; + + while (i-- > 0) + { + if (list[i] === fn || list[i]._originalHandler === fn) + { + list.splice(i, 1); + } + } + + if (list.length === 0) + { + delete this._listeners[eventName]; + } + + return this; + }; + + /** + * Remove all listeners or only the listeners for the specified event. + * + * @param eventName {string} The event you want to remove all listeners for. + */ + obj.removeAllListeners = function removeAllListeners(eventName) + { + this._listeners = this._listeners || {}; + + if (!this._listeners[eventName]) + { + return this; + } + + delete this._listeners[eventName]; + + return this; + }; +} + +module.exports = { + /** + * Mixes in the properties of the eventTarget into another object + * + * @param object {object} The obj to mix into + */ + mixin: function mixin(obj) + { + eventTarget(obj); + } +}; diff --git a/src/core/utils/pluginTarget.js b/src/core/utils/pluginTarget.js index d38508c..3f0e9ae 100644 --- a/src/core/utils/pluginTarget.js +++ b/src/core/utils/pluginTarget.js @@ -34,9 +34,10 @@ }; } + module.exports = { /** - * Mixes in the properties of the eventTarget prototype onto another object + * Mixes in the properties of the pluginTarget into another object * * @param object {object} The obj to mix into */