2016-10-04 14:39:54 +00:00
|
|
|
/**
|
|
|
|
* @author Richard Davey <rich@photonstorm.com>
|
|
|
|
* @author Mat Groves (@Doormat23)
|
|
|
|
* @copyright 2016 Photon Storm Ltd.
|
|
|
|
* @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* New version of PIXI.WebGLSpriteBatch
|
|
|
|
*
|
|
|
|
* @class Phaser.Renderer.Canvas
|
|
|
|
* @constructor
|
|
|
|
* @param {Phaser.Game} game - Game reference to the currently running game.
|
|
|
|
*/
|
2016-10-24 16:14:10 +00:00
|
|
|
Phaser.Renderer.WebGL.BatchManager = function (renderer, batchSize)
|
2016-10-04 14:39:54 +00:00
|
|
|
{
|
|
|
|
this.renderer = renderer;
|
|
|
|
|
|
|
|
this.gl = null;
|
|
|
|
|
2016-10-18 23:23:40 +00:00
|
|
|
// Total number of objects we'll batch before flushing and rendering
|
2016-10-24 16:14:10 +00:00
|
|
|
this.maxBatchSize = batchSize;
|
2016-10-18 23:23:40 +00:00
|
|
|
|
|
|
|
this.halfBatchSize = this.maxBatchSize / 2;
|
|
|
|
|
2016-10-19 00:56:31 +00:00
|
|
|
// Vertex Data Size is calculated by adding together:
|
2016-10-18 23:23:40 +00:00
|
|
|
//
|
2016-10-20 04:04:06 +00:00
|
|
|
// Position (vec2) = 4 * 2 = 8 bytes
|
|
|
|
// UV (vec2) = 4 * 2 = 8 bytes
|
|
|
|
// Texture Index (float) = 4 bytes
|
2016-10-19 02:55:28 +00:00
|
|
|
// Tint Color (float) = 4 bytes
|
|
|
|
// BG Color (float) = 4 bytes
|
2016-10-28 01:42:58 +00:00
|
|
|
//
|
|
|
|
// Total: 28 bytes (per vert) * 4 (4 verts per quad) (= 112 bytes) * maxBatchSize (usually 2000) = 224 kilobytes sent to the GPU every frame
|
2016-10-18 23:23:40 +00:00
|
|
|
|
2016-10-20 04:04:06 +00:00
|
|
|
this.vertSize = (4 * 2) + (4 * 2) + (4) + (4) + (4);
|
2016-10-18 23:23:40 +00:00
|
|
|
|
|
|
|
var numVerts = this.vertSize * this.maxBatchSize * 4;
|
|
|
|
|
|
|
|
this.vertices = new ArrayBuffer(numVerts);
|
|
|
|
|
|
|
|
// Number of total quads allowed in the batch * 6
|
|
|
|
// 6 because there are 2 triangles per quad, and each triangle has 3 indices
|
|
|
|
this.indices = new Uint16Array(this.maxBatchSize * 6);
|
|
|
|
|
2016-10-04 14:39:54 +00:00
|
|
|
// View on the vertices as a Float32Array
|
|
|
|
this.positions = new Float32Array(this.vertices);
|
|
|
|
|
|
|
|
// View on the vertices as a Uint32Array
|
2016-10-19 00:56:31 +00:00
|
|
|
this.colors = new Uint32Array(this.vertices);
|
2016-10-04 14:39:54 +00:00
|
|
|
|
|
|
|
this.currentBatchSize = 0;
|
2016-10-25 02:57:34 +00:00
|
|
|
|
2016-10-04 14:39:54 +00:00
|
|
|
this.dirty = true;
|
2016-10-25 02:57:34 +00:00
|
|
|
|
2016-10-24 16:14:10 +00:00
|
|
|
this.list = [];
|
2016-10-18 16:03:25 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* The WebGL program.
|
|
|
|
* @property program
|
|
|
|
* @type Any
|
|
|
|
*/
|
|
|
|
this.program = null;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The Default Vertex shader source.
|
|
|
|
*
|
|
|
|
* @property defaultVertexSrc
|
|
|
|
* @type String
|
2016-10-19 00:56:31 +00:00
|
|
|
*/
|
|
|
|
this.vertexSrc = [
|
2016-10-18 16:03:25 +00:00
|
|
|
'attribute vec2 aVertexPosition;',
|
|
|
|
'attribute vec2 aTextureCoord;',
|
2016-10-20 04:04:06 +00:00
|
|
|
'attribute float aTextureIndex;',
|
2016-10-19 02:55:28 +00:00
|
|
|
'attribute vec4 aTintColor;',
|
|
|
|
'attribute vec4 aBgColor;',
|
2016-10-18 16:03:25 +00:00
|
|
|
|
|
|
|
'uniform vec2 projectionVector;',
|
2016-10-20 14:01:22 +00:00
|
|
|
'uniform vec2 offsetVector;',
|
2016-10-18 16:03:25 +00:00
|
|
|
|
|
|
|
'varying vec2 vTextureCoord;',
|
2016-10-19 02:55:28 +00:00
|
|
|
'varying vec4 vTintColor;',
|
|
|
|
'varying vec4 vBgColor;',
|
2016-10-20 04:04:06 +00:00
|
|
|
'varying float vTextureIndex;',
|
2016-10-18 16:03:25 +00:00
|
|
|
|
|
|
|
'const vec2 center = vec2(-1.0, 1.0);',
|
|
|
|
|
|
|
|
'void main(void) {',
|
2016-10-20 14:01:22 +00:00
|
|
|
' if (aTextureIndex > 0.0) gl_Position = vec4(0.0);',
|
|
|
|
' gl_Position = vec4(((aVertexPosition + offsetVector) / projectionVector) + center, 0.0, 1.0);',
|
2016-10-18 23:23:40 +00:00
|
|
|
' vTextureCoord = aTextureCoord;', // pass the texture coordinate to the fragment shader, the GPU will interpolate the points
|
2016-10-19 02:55:28 +00:00
|
|
|
' vTintColor = vec4(aTintColor.rgb * aTintColor.a, aTintColor.a);',
|
|
|
|
' vBgColor = aBgColor;',
|
2016-10-20 13:33:31 +00:00
|
|
|
' vTextureIndex = aTextureIndex;',
|
2016-10-18 23:23:40 +00:00
|
|
|
'}'
|
|
|
|
];
|
2016-10-18 16:03:25 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* The fragment shader.
|
|
|
|
* @property fragmentSrc
|
|
|
|
* @type Array
|
2016-10-19 00:56:31 +00:00
|
|
|
*/
|
2016-10-18 23:23:40 +00:00
|
|
|
this.fragmentSrc = [
|
2016-10-20 13:33:31 +00:00
|
|
|
'precision lowp float;',
|
2016-10-19 02:55:28 +00:00
|
|
|
|
2016-10-18 23:23:40 +00:00
|
|
|
'varying vec2 vTextureCoord;', // the texture coords passed in from the vertex shader
|
2016-10-19 02:55:28 +00:00
|
|
|
'varying vec4 vTintColor;', // the color value passed in from the vertex shader (texture color + alpha + tint)
|
|
|
|
'varying vec4 vBgColor;', // the bg color value passed in from the vertex shader
|
2016-10-19 00:56:31 +00:00
|
|
|
'varying float vTextureIndex;',
|
2016-10-19 02:55:28 +00:00
|
|
|
|
2016-10-18 23:23:40 +00:00
|
|
|
'uniform sampler2D uSampler;', // our texture
|
2016-10-19 02:55:28 +00:00
|
|
|
|
2016-10-18 23:23:40 +00:00
|
|
|
'void main(void) {',
|
2016-10-25 15:44:23 +00:00
|
|
|
' vec4 pixel = texture2D(uSampler, vTextureCoord) * vTintColor;', // get the color from the texture
|
2016-10-25 02:57:34 +00:00
|
|
|
// ' if (pixel.a == 0.0) pixel = vBgColor;', // if texture alpha is zero, use the bg color
|
2016-10-19 02:55:28 +00:00
|
|
|
' gl_FragColor = pixel;',
|
2016-10-18 16:03:25 +00:00
|
|
|
'}'
|
|
|
|
];
|
|
|
|
|
2016-10-28 01:42:58 +00:00
|
|
|
this.fragmentSrc2 = [
|
|
|
|
'precision lowp float;',
|
|
|
|
|
|
|
|
'varying vec2 vTextureCoord;', // the texture coords passed in from the vertex shader
|
|
|
|
'varying vec4 vTintColor;', // the color value passed in from the vertex shader (texture color + alpha + tint)
|
|
|
|
'varying vec4 vBgColor;', // the bg color value passed in from the vertex shader
|
|
|
|
'varying float vTextureIndex;',
|
|
|
|
|
|
|
|
'uniform sampler2D uSampler;', // our texture
|
|
|
|
|
|
|
|
'void main(void) {',
|
|
|
|
' gl_FragColor = texture2D(uSampler, vTextureCoord);',
|
|
|
|
' gl_FragColor.rgb = mix(gl_FragColor.rgb, vec3(0.2126 * gl_FragColor.r + 0.7152 * gl_FragColor.g + 0.0722 * gl_FragColor.b), 1.0);',
|
|
|
|
'}'
|
|
|
|
];
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The multi-texture fragment shader.
|
|
|
|
* This array is modified heavily by the initMultiTexture method.
|
|
|
|
* @property multiTextureFragmentSrc
|
|
|
|
* @type Array
|
|
|
|
*/
|
|
|
|
this.multiTextureFragmentSrc = [
|
|
|
|
'precision lowp float;',
|
|
|
|
|
|
|
|
'varying vec2 vTextureCoord;', // the texture coords passed in from the vertex shader
|
|
|
|
'varying vec4 vTintColor;', // the color value passed in from the vertex shader (texture color + alpha + tint)
|
|
|
|
'varying vec4 vBgColor;', // the bg color value passed in from the vertex shader
|
|
|
|
'varying float vTextureIndex;',
|
|
|
|
|
|
|
|
'uniform sampler2D uSamplerArray[0];', // this line is replaced when the shader is built, with the actual total
|
|
|
|
|
|
|
|
'const vec4 PINK = vec4(1.0, 0.0, 1.0, 1.0);',
|
|
|
|
|
|
|
|
'void main(void) {',
|
|
|
|
' vec4 pixel;',
|
|
|
|
' if (vTextureIndex == 0.0) pixel = texture2D(uSamplerArray[0], vTextureCoord);',
|
|
|
|
'// IFELSEBLOCK', // special tag used to insert the multi-texture if else block. Do not edit or remove.
|
|
|
|
' else pixel = PINK;',
|
|
|
|
' pixel *= vTintColor;',
|
|
|
|
// ' if (pixel.a == 0.0) pixel = vBgColor;', // if texture alpha is zero, use the bg color
|
|
|
|
' gl_FragColor = pixel;',
|
|
|
|
'}'
|
|
|
|
];
|
2016-10-24 23:41:45 +00:00
|
|
|
|
2016-10-18 16:03:25 +00:00
|
|
|
// @type {GLint}
|
2016-10-20 04:04:06 +00:00
|
|
|
this.aVertexPosition;
|
2016-10-19 02:55:28 +00:00
|
|
|
|
|
|
|
// @type {GLint}
|
2016-10-20 04:04:06 +00:00
|
|
|
this.aTextureCoord;
|
2016-10-18 16:03:25 +00:00
|
|
|
|
|
|
|
// @type {GLint}
|
|
|
|
this.aTextureIndex;
|
|
|
|
|
|
|
|
// @type {GLint}
|
2016-10-20 04:04:06 +00:00
|
|
|
this.aTintColor;
|
2016-10-18 16:03:25 +00:00
|
|
|
|
|
|
|
// @type {GLint}
|
2016-10-20 04:04:06 +00:00
|
|
|
this.aBgColor;
|
2016-10-20 13:33:31 +00:00
|
|
|
|
|
|
|
// @type {WebGLUniformLocation }
|
|
|
|
this.uSampler;
|
|
|
|
|
|
|
|
// @type {WebGLUniformLocation }
|
|
|
|
this.projectionVector;
|
2016-10-20 14:01:22 +00:00
|
|
|
|
|
|
|
// @type {WebGLUniformLocation }
|
|
|
|
this.offsetVector;
|
2016-10-23 10:25:44 +00:00
|
|
|
|
|
|
|
this._i = 0;
|
2016-10-04 14:39:54 +00:00
|
|
|
};
|
|
|
|
|
2016-10-07 01:09:12 +00:00
|
|
|
Phaser.Renderer.WebGL.BatchManager.prototype.constructor = Phaser.Renderer.WebGL.BatchManager;
|
2016-10-04 14:39:54 +00:00
|
|
|
|
2016-10-07 01:09:12 +00:00
|
|
|
Phaser.Renderer.WebGL.BatchManager.prototype = {
|
2016-10-04 14:39:54 +00:00
|
|
|
|
|
|
|
init: function ()
|
|
|
|
{
|
|
|
|
this.gl = this.renderer.gl;
|
|
|
|
|
2016-10-18 23:23:40 +00:00
|
|
|
// Our static index buffer, calculated once at the start of our game
|
|
|
|
|
|
|
|
// This contains the indices data for the quads.
|
|
|
|
//
|
|
|
|
// A quad is made up of 2 triangles (A and B in the image below)
|
|
|
|
//
|
|
|
|
// 0 = Top Left
|
|
|
|
// 1 = Top Right
|
|
|
|
// 2 = Bottom Right
|
|
|
|
// 3 = Bottom Left
|
|
|
|
//
|
|
|
|
// 0----1
|
|
|
|
// |\ A|
|
|
|
|
// | \ |
|
|
|
|
// | \ |
|
|
|
|
// | B \|
|
|
|
|
// | \
|
|
|
|
// 3----2
|
|
|
|
//
|
|
|
|
// Because triangles A and B share 2 points (0 and 2) the vertex buffer only stores
|
|
|
|
// 4 sets of data (top-left, top-right, bottom-left and bottom-right), which is why
|
|
|
|
// the indices offsets uses the j += 4 iteration. Indices array has to contain 3
|
|
|
|
// entries for every triangle (so 6 for every quad), but our vertex data compacts
|
|
|
|
// that down, as we don't want to fill it with loads of DUPLICATE data, so the
|
|
|
|
// indices array is a look-up table, telling WebGL where in the vertex buffer to look
|
|
|
|
// for that triangles indice data.
|
|
|
|
|
|
|
|
// batchSize * vertSize = 2000 * 6 (because we store 6 pieces of vertex data per triangle)
|
|
|
|
// and up to a maximum of 2000 entries in the batch
|
|
|
|
|
|
|
|
for (var i = 0, j = 0; i < (this.maxBatchSize * this.vertSize); i += 6, j += 4)
|
|
|
|
{
|
|
|
|
// Triangle 1
|
|
|
|
this.indices[i + 0] = j + 0; // Top Left
|
|
|
|
this.indices[i + 1] = j + 1; // Top Right
|
|
|
|
this.indices[i + 2] = j + 2; // Bottom Right
|
|
|
|
|
|
|
|
// Triangle 2
|
|
|
|
this.indices[i + 3] = j + 0; // Top Left
|
|
|
|
this.indices[i + 4] = j + 2; // Bottom Right
|
|
|
|
this.indices[i + 5] = j + 3; // Bottom Left
|
|
|
|
}
|
|
|
|
|
2016-10-19 00:56:31 +00:00
|
|
|
var gl = this.gl;
|
2016-10-18 16:03:25 +00:00
|
|
|
|
2016-10-19 00:56:31 +00:00
|
|
|
// Create indices buffer
|
|
|
|
this.indexBuffer = gl.createBuffer();
|
2016-10-18 16:03:25 +00:00
|
|
|
|
2016-10-19 00:56:31 +00:00
|
|
|
// Bind it
|
|
|
|
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer);
|
|
|
|
|
|
|
|
// Set the source of the buffer data (this.indices array)
|
|
|
|
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, this.indices, gl.STATIC_DRAW);
|
|
|
|
|
|
|
|
// Create Vertex Data buffer
|
|
|
|
this.vertexBuffer = gl.createBuffer();
|
|
|
|
|
|
|
|
// Bind it
|
|
|
|
gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer);
|
|
|
|
|
|
|
|
// Set the source of the buffer data (this.vertices array)
|
|
|
|
gl.bufferData(gl.ARRAY_BUFFER, this.vertices, gl.DYNAMIC_DRAW);
|
|
|
|
|
2016-10-25 02:57:34 +00:00
|
|
|
if (this.renderer.multiTexture)
|
2016-10-24 23:41:45 +00:00
|
|
|
{
|
2016-10-25 15:44:23 +00:00
|
|
|
this.initMultiTexture();
|
2016-10-24 23:41:45 +00:00
|
|
|
}
|
2016-10-25 15:44:23 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
this.initSingleTexture();
|
|
|
|
}
|
|
|
|
},
|
2016-10-24 23:41:45 +00:00
|
|
|
|
2016-10-28 01:42:58 +00:00
|
|
|
initAttributes: function (p)
|
2016-10-25 15:44:23 +00:00
|
|
|
{
|
|
|
|
var gl = this.gl;
|
2016-10-28 01:42:58 +00:00
|
|
|
// var program = this.program2;
|
|
|
|
var program = p;
|
|
|
|
|
|
|
|
// Set Shader
|
|
|
|
gl.useProgram(program);
|
2016-10-18 16:03:25 +00:00
|
|
|
|
|
|
|
// Get and store the attributes
|
2016-10-20 13:33:31 +00:00
|
|
|
|
|
|
|
// vertex position
|
2016-10-18 16:03:25 +00:00
|
|
|
this.aVertexPosition = gl.getAttribLocation(program, 'aVertexPosition');
|
2016-10-20 13:33:31 +00:00
|
|
|
gl.enableVertexAttribArray(this.aVertexPosition);
|
|
|
|
|
2016-10-25 15:44:23 +00:00
|
|
|
// texture coordinate
|
2016-10-18 16:03:25 +00:00
|
|
|
this.aTextureCoord = gl.getAttribLocation(program, 'aTextureCoord');
|
2016-10-20 13:33:31 +00:00
|
|
|
gl.enableVertexAttribArray(this.aTextureCoord);
|
|
|
|
|
2016-10-25 15:44:23 +00:00
|
|
|
// texture index
|
2016-10-20 04:04:06 +00:00
|
|
|
this.aTextureIndex = gl.getAttribLocation(program, 'aTextureIndex');
|
2016-10-20 13:33:31 +00:00
|
|
|
gl.enableVertexAttribArray(this.aTextureIndex);
|
|
|
|
|
2016-10-25 15:44:23 +00:00
|
|
|
// tint / pixel color
|
2016-10-19 02:55:28 +00:00
|
|
|
this.aTintColor = gl.getAttribLocation(program, 'aTintColor');
|
2016-10-20 13:33:31 +00:00
|
|
|
gl.enableVertexAttribArray(this.aTintColor);
|
|
|
|
|
2016-10-25 15:44:23 +00:00
|
|
|
// background pixel color
|
2016-10-19 02:55:28 +00:00
|
|
|
this.aBgColor = gl.getAttribLocation(program, 'aBgColor');
|
2016-10-20 13:33:31 +00:00
|
|
|
gl.enableVertexAttribArray(this.aBgColor);
|
2016-10-18 16:03:25 +00:00
|
|
|
|
2016-10-25 15:44:23 +00:00
|
|
|
// The projection vector (middle of the game world)
|
|
|
|
this.projectionVector = gl.getUniformLocation(program, 'projectionVector');
|
|
|
|
|
|
|
|
// The offset vector (camera shake)
|
|
|
|
this.offsetVector = gl.getUniformLocation(program, 'offsetVector');
|
|
|
|
},
|
|
|
|
|
|
|
|
initSingleTexture: function ()
|
|
|
|
{
|
|
|
|
var gl = this.gl;
|
|
|
|
|
|
|
|
// Shader already exists
|
|
|
|
if (this.program)
|
2016-10-24 23:41:45 +00:00
|
|
|
{
|
2016-10-25 15:44:23 +00:00
|
|
|
this.renderer.deleteProgram(this.program);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Compile the Shader
|
|
|
|
this.program = this.renderer.compileProgram(this.vertexSrc, this.fragmentSrc);
|
|
|
|
|
2016-10-28 01:42:58 +00:00
|
|
|
this.program2 = this.renderer.compileProgram(this.vertexSrc, this.fragmentSrc2);
|
|
|
|
|
2016-10-25 15:44:23 +00:00
|
|
|
// Set Shader
|
2016-10-28 01:42:58 +00:00
|
|
|
// gl.useProgram(this.program);
|
2016-10-25 15:44:23 +00:00
|
|
|
|
2016-10-28 01:42:58 +00:00
|
|
|
this.initAttributes(this.program);
|
2016-10-25 15:44:23 +00:00
|
|
|
|
|
|
|
this.uSampler = gl.getUniformLocation(this.program, 'uSampler');
|
|
|
|
},
|
|
|
|
|
|
|
|
initMultiTexture: function ()
|
|
|
|
{
|
|
|
|
var gl = this.gl;
|
|
|
|
|
2016-10-28 01:42:58 +00:00
|
|
|
var block = [];
|
|
|
|
var splicePoint = 0;
|
2016-10-04 14:39:54 +00:00
|
|
|
|
2016-10-28 01:42:58 +00:00
|
|
|
// Build the else if block
|
|
|
|
for (var t = 1; t < this.renderer.maxTextures; t++)
|
2016-10-25 15:44:23 +00:00
|
|
|
{
|
2016-10-28 01:42:58 +00:00
|
|
|
block.push(' else if (vTextureIndex == ' + t + '.0) pixel = texture2D(uSamplerArray[' + t + '], vTextureCoord);');
|
2016-10-04 14:39:54 +00:00
|
|
|
}
|
2016-10-25 15:44:23 +00:00
|
|
|
|
2016-10-28 01:42:58 +00:00
|
|
|
// Parse the fragment src array
|
|
|
|
for (var i = 0; i < this.multiTextureFragmentSrc.length; i++)
|
|
|
|
{
|
|
|
|
var line = this.multiTextureFragmentSrc[i];
|
2016-10-25 15:44:23 +00:00
|
|
|
|
2016-10-28 01:42:58 +00:00
|
|
|
// Inject the maxTextures total into the shader
|
|
|
|
if (line === 'uniform sampler2D uSamplerArray[0];')
|
|
|
|
{
|
|
|
|
this.multiTextureFragmentSrc[i] = 'uniform sampler2D uSamplerArray[' + this.renderer.maxTextures + '];';
|
|
|
|
}
|
|
|
|
else if (line === '// IFELSEBLOCK')
|
|
|
|
{
|
|
|
|
// Store the index at which we need to insert the if else block
|
|
|
|
splicePoint = i;
|
|
|
|
}
|
|
|
|
}
|
2016-10-25 15:44:23 +00:00
|
|
|
|
2016-10-28 01:42:58 +00:00
|
|
|
// Store the end part of the shader
|
|
|
|
var shaderEnd = this.multiTextureFragmentSrc.splice(splicePoint);
|
2016-10-25 15:44:23 +00:00
|
|
|
|
2016-10-28 01:42:58 +00:00
|
|
|
// Stitch it back together again
|
|
|
|
this.multiTextureFragmentSrc = this.multiTextureFragmentSrc.concat(block, shaderEnd);
|
|
|
|
|
|
|
|
// Shader already exists?
|
2016-10-25 15:44:23 +00:00
|
|
|
if (this.program)
|
2016-10-04 14:39:54 +00:00
|
|
|
{
|
2016-10-25 15:44:23 +00:00
|
|
|
this.renderer.deleteProgram(this.program);
|
2016-10-04 14:39:54 +00:00
|
|
|
}
|
2016-10-24 23:41:45 +00:00
|
|
|
|
2016-10-25 15:44:23 +00:00
|
|
|
// Compile the Shader
|
|
|
|
this.program = this.renderer.compileProgram(this.vertexSrc, this.multiTextureFragmentSrc);
|
2016-10-24 23:41:45 +00:00
|
|
|
|
2016-10-25 15:44:23 +00:00
|
|
|
// Set Shader
|
|
|
|
gl.useProgram(this.program);
|
|
|
|
|
|
|
|
this.initAttributes();
|
|
|
|
|
|
|
|
// Bind empty multi-textures to avoid WebGL spam
|
|
|
|
var indices = [];
|
|
|
|
|
|
|
|
var tempTexture = this.renderer.createEmptyTexture(1, 1, 0);
|
|
|
|
|
|
|
|
for (i = 0; i < this.renderer.maxTextures; i++)
|
|
|
|
{
|
|
|
|
gl.activeTexture(gl.TEXTURE0 + i);
|
|
|
|
|
|
|
|
gl.bindTexture(gl.TEXTURE_2D, tempTexture);
|
|
|
|
|
|
|
|
indices.push(i);
|
|
|
|
}
|
|
|
|
|
|
|
|
this.uSampler = gl.getUniformLocation(this.program, 'uSamplerArray[0]');
|
2016-10-24 23:41:45 +00:00
|
|
|
|
2016-10-25 15:44:23 +00:00
|
|
|
gl.uniform1iv(this.uSampler, indices);
|
2016-10-04 14:39:54 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
begin: function ()
|
|
|
|
{
|
2016-10-24 16:14:10 +00:00
|
|
|
this._i = 0;
|
|
|
|
this.dirty = true;
|
2016-10-25 00:40:16 +00:00
|
|
|
this.currentBatchSize = 0;
|
2016-10-28 01:42:58 +00:00
|
|
|
this.initAttributes(this.program);
|
2016-10-04 14:39:54 +00:00
|
|
|
},
|
|
|
|
|
2016-10-24 16:14:10 +00:00
|
|
|
end: function ()
|
2016-10-18 16:03:25 +00:00
|
|
|
{
|
2016-10-24 16:14:10 +00:00
|
|
|
if (this.currentBatchSize > 0)
|
|
|
|
{
|
|
|
|
this.flush();
|
|
|
|
}
|
2016-10-04 14:39:54 +00:00
|
|
|
},
|
|
|
|
|
2016-10-24 16:14:10 +00:00
|
|
|
start: function ()
|
2016-10-04 14:39:54 +00:00
|
|
|
{
|
2016-10-24 16:14:10 +00:00
|
|
|
this._i = 0;
|
|
|
|
this.dirty = true;
|
2016-10-04 14:39:54 +00:00
|
|
|
},
|
|
|
|
|
2016-10-18 16:03:25 +00:00
|
|
|
stop: function ()
|
|
|
|
{
|
2016-10-24 16:14:10 +00:00
|
|
|
if (this.currentBatchSize > 0)
|
|
|
|
{
|
|
|
|
this.flush();
|
|
|
|
}
|
|
|
|
|
2016-10-04 14:39:54 +00:00
|
|
|
this.dirty = true;
|
|
|
|
},
|
|
|
|
|
2016-10-27 14:14:22 +00:00
|
|
|
setCurrentTexture: function (source)
|
2016-10-19 10:54:00 +00:00
|
|
|
{
|
2016-10-27 14:14:22 +00:00
|
|
|
var gl = this.gl;
|
2016-10-19 10:54:00 +00:00
|
|
|
|
2016-10-27 14:14:22 +00:00
|
|
|
if (this.currentBatchSize > 0)
|
|
|
|
{
|
|
|
|
this.flush();
|
|
|
|
}
|
2016-10-25 00:40:16 +00:00
|
|
|
|
2016-10-27 14:14:22 +00:00
|
|
|
gl.activeTexture(gl.TEXTURE0 + source.glTextureIndex);
|
2016-10-19 10:54:00 +00:00
|
|
|
|
2016-10-27 14:14:22 +00:00
|
|
|
gl.bindTexture(gl.TEXTURE_2D, source.glTexture);
|
2016-10-19 10:54:00 +00:00
|
|
|
|
2016-10-27 14:14:22 +00:00
|
|
|
this.renderer.textureArray[source.glTextureIndex] = source;
|
2016-10-22 17:02:43 +00:00
|
|
|
},
|
|
|
|
|
2016-10-25 13:30:29 +00:00
|
|
|
add: function (gameObject, verts, uvs, textureIndex, alpha, tintColors, bgColors)
|
2016-10-22 17:02:43 +00:00
|
|
|
{
|
2016-10-25 00:40:16 +00:00
|
|
|
// console.log('addToBatch', gameObject.frame.name);
|
2016-10-24 16:14:10 +00:00
|
|
|
|
|
|
|
// Check Batch Size and flush if needed
|
|
|
|
if (this.currentBatchSize >= this.maxBatchSize)
|
|
|
|
{
|
|
|
|
this.flush();
|
|
|
|
}
|
|
|
|
|
2016-10-25 02:57:34 +00:00
|
|
|
var source = gameObject.frame.source;
|
|
|
|
|
2016-10-25 12:23:14 +00:00
|
|
|
source.glLastUsed = this.renderer.startTime;
|
|
|
|
|
2016-10-25 00:40:16 +00:00
|
|
|
// Does this Game Objects texture need updating?
|
2016-10-25 02:57:34 +00:00
|
|
|
if (source.glDirty)
|
2016-10-25 00:40:16 +00:00
|
|
|
{
|
2016-10-25 02:57:34 +00:00
|
|
|
this.renderer.updateTexture(source);
|
2016-10-25 00:40:16 +00:00
|
|
|
}
|
|
|
|
|
2016-10-27 14:14:22 +00:00
|
|
|
// Does the batch need to activate a new texture?
|
2016-10-25 02:57:34 +00:00
|
|
|
if (this.renderer.textureArray[source.glTextureIndex] !== source)
|
|
|
|
{
|
2016-10-27 14:14:22 +00:00
|
|
|
this.setCurrentTexture(source);
|
2016-10-25 02:57:34 +00:00
|
|
|
}
|
2016-10-24 16:14:10 +00:00
|
|
|
|
|
|
|
// These are TypedArray Views into the vertices ArrayBuffer
|
2016-10-22 17:02:43 +00:00
|
|
|
var colors = this.colors;
|
|
|
|
var positions = this.positions;
|
|
|
|
|
2016-10-24 16:14:10 +00:00
|
|
|
var i = this._i;
|
2016-10-22 17:02:43 +00:00
|
|
|
|
|
|
|
// Top Left vert (xy, uv, color)
|
|
|
|
positions[i++] = verts.x0;
|
|
|
|
positions[i++] = verts.y0;
|
|
|
|
positions[i++] = uvs.x0;
|
|
|
|
positions[i++] = uvs.y0;
|
|
|
|
positions[i++] = textureIndex;
|
2016-10-24 16:14:10 +00:00
|
|
|
colors[i++] = tintColors.topLeft + alpha;
|
2016-10-22 17:02:43 +00:00
|
|
|
colors[i++] = bgColors.topLeft;
|
|
|
|
|
|
|
|
// Top Right vert (xy, uv, color)
|
|
|
|
positions[i++] = verts.x1;
|
|
|
|
positions[i++] = verts.y1;
|
|
|
|
positions[i++] = uvs.x1;
|
|
|
|
positions[i++] = uvs.y1;
|
|
|
|
positions[i++] = textureIndex;
|
2016-10-24 16:14:10 +00:00
|
|
|
colors[i++] = tintColors.topRight + alpha;
|
2016-10-22 17:02:43 +00:00
|
|
|
colors[i++] = bgColors.topRight;
|
|
|
|
|
|
|
|
// Bottom Right vert (xy, uv, color)
|
|
|
|
positions[i++] = verts.x2;
|
|
|
|
positions[i++] = verts.y2;
|
|
|
|
positions[i++] = uvs.x2;
|
|
|
|
positions[i++] = uvs.y2;
|
|
|
|
positions[i++] = textureIndex;
|
2016-10-24 16:14:10 +00:00
|
|
|
colors[i++] = tintColors.bottomRight + alpha;
|
2016-10-22 17:02:43 +00:00
|
|
|
colors[i++] = bgColors.bottomRight;
|
|
|
|
|
|
|
|
// Bottom Left vert (xy, uv, color)
|
|
|
|
positions[i++] = verts.x3;
|
|
|
|
positions[i++] = verts.y3;
|
|
|
|
positions[i++] = uvs.x3;
|
|
|
|
positions[i++] = uvs.y3;
|
|
|
|
positions[i++] = textureIndex;
|
2016-10-24 16:14:10 +00:00
|
|
|
colors[i++] = tintColors.bottomLeft + alpha;
|
2016-10-22 17:02:43 +00:00
|
|
|
colors[i++] = bgColors.bottomLeft;
|
|
|
|
|
2016-10-24 16:14:10 +00:00
|
|
|
this._i = i;
|
|
|
|
|
|
|
|
this.list[this.currentBatchSize++] = gameObject;
|
2016-10-22 17:02:43 +00:00
|
|
|
},
|
|
|
|
|
2016-10-24 23:41:45 +00:00
|
|
|
initShader: function ()
|
2016-10-04 14:39:54 +00:00
|
|
|
{
|
|
|
|
var gl = this.gl;
|
|
|
|
|
2016-10-24 16:14:10 +00:00
|
|
|
// Bind the buffers
|
2016-10-28 01:42:58 +00:00
|
|
|
// gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer);
|
|
|
|
// gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer);
|
2016-10-04 14:39:54 +00:00
|
|
|
|
2016-10-24 16:14:10 +00:00
|
|
|
// Set the projection vector. Defaults to the middle of the Game World, on negative y.
|
|
|
|
// I.e. if the world is 800x600 then the projection vector is 400 x -300
|
|
|
|
gl.uniform2f(this.projectionVector, this.renderer.projection.x, this.renderer.projection.y);
|
2016-10-04 14:39:54 +00:00
|
|
|
|
2016-10-24 16:14:10 +00:00
|
|
|
// Set the offset vector.
|
|
|
|
gl.uniform2f(this.offsetVector, this.renderer.offset.x, this.renderer.offset.y);
|
2016-10-04 14:39:54 +00:00
|
|
|
|
2016-10-24 16:14:10 +00:00
|
|
|
// The Vertex Position (x/y)
|
|
|
|
// 2 FLOATS, 2 * 4 = 8 bytes. Index pos: 0 to 7
|
|
|
|
// final argument = the offset within the vertex input
|
|
|
|
gl.vertexAttribPointer(this.aVertexPosition, 2, gl.FLOAT, false, this.vertSize, 0);
|
2016-10-20 14:01:22 +00:00
|
|
|
|
2016-10-24 16:14:10 +00:00
|
|
|
// The Texture Coordinate (uvx/uvy)
|
|
|
|
// 2 FLOATS, 2 * 4 = 8 bytes. Index pos: 8 to 15
|
|
|
|
gl.vertexAttribPointer(this.aTextureCoord, 2, gl.FLOAT, false, this.vertSize, 8);
|
2016-10-18 16:03:25 +00:00
|
|
|
|
2016-10-24 16:14:10 +00:00
|
|
|
// Texture Index
|
|
|
|
// 1 FLOAT, 4 bytes. Index pos: 16 to 19
|
|
|
|
gl.vertexAttribPointer(this.aTextureIndex, 1, gl.FLOAT, false, this.vertSize, 16);
|
2016-10-18 16:03:25 +00:00
|
|
|
|
2016-10-24 16:14:10 +00:00
|
|
|
// Tint color
|
|
|
|
// 4 UNSIGNED BYTES, 4 bytes. Index pos: 20 to 23
|
|
|
|
// Attributes will be interpreted as unsigned bytes and normalized
|
|
|
|
gl.vertexAttribPointer(this.aTintColor, 4, gl.UNSIGNED_BYTE, true, this.vertSize, 20);
|
2016-10-19 02:55:28 +00:00
|
|
|
|
2016-10-24 16:14:10 +00:00
|
|
|
// Background Color
|
|
|
|
// 4 UNSIGNED BYTES, 4 bytes. Index pos: 24 to 27
|
|
|
|
// Attributes will be interpreted as unsigned bytes and normalized
|
|
|
|
gl.vertexAttribPointer(this.aBgColor, 4, gl.UNSIGNED_BYTE, true, this.vertSize, 24);
|
2016-10-18 16:03:25 +00:00
|
|
|
|
2016-10-24 16:14:10 +00:00
|
|
|
this.dirty = false;
|
|
|
|
},
|
|
|
|
|
|
|
|
flush: function ()
|
|
|
|
{
|
2016-10-28 01:42:58 +00:00
|
|
|
var gl = this.gl;
|
|
|
|
|
2016-10-24 16:14:10 +00:00
|
|
|
// Always dirty the first pass through but subsequent calls may be clean
|
|
|
|
if (this.dirty)
|
|
|
|
{
|
2016-10-28 01:42:58 +00:00
|
|
|
gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer);
|
|
|
|
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer);
|
|
|
|
|
2016-10-24 23:41:45 +00:00
|
|
|
this.initShader();
|
2016-10-04 14:39:54 +00:00
|
|
|
}
|
|
|
|
|
2016-10-25 02:57:34 +00:00
|
|
|
// Upload the vertex data to the GPU - is this cheaper (overall) than creating a new TypedArray view?
|
|
|
|
gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.vertices);
|
|
|
|
|
|
|
|
/*
|
2016-10-18 23:23:40 +00:00
|
|
|
if (this.currentBatchSize > this.halfBatchSize)
|
2016-10-04 14:39:54 +00:00
|
|
|
{
|
|
|
|
gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.vertices);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer);
|
2016-10-18 16:03:25 +00:00
|
|
|
|
2016-10-24 16:14:10 +00:00
|
|
|
// This creates a brand new Typed Array - what's the cost of this vs. just uploading all vert data?
|
2016-10-19 00:56:31 +00:00
|
|
|
var view = this.positions.subarray(0, this.currentBatchSize * this.vertSize);
|
2016-10-18 16:03:25 +00:00
|
|
|
|
2016-10-04 14:39:54 +00:00
|
|
|
gl.bufferSubData(gl.ARRAY_BUFFER, 0, view);
|
|
|
|
}
|
2016-10-25 02:57:34 +00:00
|
|
|
*/
|
2016-10-04 14:39:54 +00:00
|
|
|
|
2016-10-18 16:03:25 +00:00
|
|
|
var sprite;
|
|
|
|
|
2016-10-04 14:39:54 +00:00
|
|
|
var start = 0;
|
2016-10-18 16:03:25 +00:00
|
|
|
var currentSize = 0;
|
2016-10-04 14:39:54 +00:00
|
|
|
|
2016-10-18 16:03:25 +00:00
|
|
|
for (var i = 0; i < this.currentBatchSize; i++)
|
2016-10-04 14:39:54 +00:00
|
|
|
{
|
2016-10-24 16:14:10 +00:00
|
|
|
sprite = this.list[i];
|
2016-10-04 14:39:54 +00:00
|
|
|
|
2016-10-24 16:14:10 +00:00
|
|
|
if (sprite.blendMode !== this.renderer.currentBlendMode)
|
2016-10-04 14:39:54 +00:00
|
|
|
{
|
2016-10-25 02:57:34 +00:00
|
|
|
if (currentSize > 0)
|
|
|
|
{
|
|
|
|
gl.drawElements(gl.TRIANGLES, currentSize * 6, gl.UNSIGNED_SHORT, start * 6 * 2);
|
|
|
|
this.renderer.drawCount++;
|
2016-10-27 14:14:22 +00:00
|
|
|
|
|
|
|
// Reset the batch
|
|
|
|
start = i;
|
|
|
|
currentSize = 0;
|
2016-10-25 02:57:34 +00:00
|
|
|
}
|
|
|
|
|
2016-10-24 16:14:10 +00:00
|
|
|
this.renderer.setBlendMode(sprite.blendMode);
|
2016-10-18 16:03:25 +00:00
|
|
|
}
|
2016-10-04 14:39:54 +00:00
|
|
|
|
2016-10-28 01:42:58 +00:00
|
|
|
if (sprite.shader === 2)
|
|
|
|
{
|
|
|
|
gl.drawElements(gl.TRIANGLES, currentSize * 6, gl.UNSIGNED_SHORT, start * 6 * 2);
|
|
|
|
this.renderer.drawCount++;
|
|
|
|
|
|
|
|
// Reset the batch
|
|
|
|
start = i;
|
|
|
|
currentSize = 0;
|
|
|
|
|
|
|
|
this.initAttributes(this.program2);
|
|
|
|
this.initShader();
|
|
|
|
}
|
|
|
|
else if (sprite.shader === 1)
|
|
|
|
{
|
|
|
|
gl.drawElements(gl.TRIANGLES, currentSize * 6, gl.UNSIGNED_SHORT, start * 6 * 2);
|
|
|
|
this.renderer.drawCount++;
|
|
|
|
|
|
|
|
// Reset the batch
|
|
|
|
start = i;
|
|
|
|
currentSize = 0;
|
|
|
|
|
|
|
|
this.initAttributes(this.program);
|
|
|
|
this.initShader();
|
|
|
|
}
|
|
|
|
|
2016-10-25 02:57:34 +00:00
|
|
|
// TODO: Check for shader here
|
|
|
|
|
|
|
|
// If either blend or shader set, we need to drawElements and swap
|
|
|
|
|
2016-10-18 16:03:25 +00:00
|
|
|
currentSize++;
|
2016-10-04 14:39:54 +00:00
|
|
|
}
|
|
|
|
|
2016-10-18 16:03:25 +00:00
|
|
|
if (currentSize > 0)
|
|
|
|
{
|
2016-10-24 16:14:10 +00:00
|
|
|
gl.drawElements(gl.TRIANGLES, currentSize * 6, gl.UNSIGNED_SHORT, start * 6 * 2);
|
|
|
|
this.renderer.drawCount++;
|
2016-10-18 16:03:25 +00:00
|
|
|
}
|
2016-10-04 14:39:54 +00:00
|
|
|
|
2016-10-18 16:03:25 +00:00
|
|
|
// Reset the batch
|
2016-10-04 14:39:54 +00:00
|
|
|
this.currentBatchSize = 0;
|
2016-10-25 00:40:16 +00:00
|
|
|
this._i = 0;
|
2016-10-27 14:14:22 +00:00
|
|
|
|
2016-10-04 14:39:54 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
destroy: function ()
|
|
|
|
{
|
|
|
|
this.vertices = null;
|
|
|
|
this.indices = null;
|
|
|
|
|
|
|
|
this.gl.deleteBuffer(this.vertexBuffer);
|
|
|
|
this.gl.deleteBuffer(this.indexBuffer);
|
|
|
|
|
|
|
|
this.renderer = null;
|
|
|
|
this.gl = null;
|
|
|
|
}
|
|
|
|
|
|
|
|
};
|