|
| 1 | +var BindVertexArray = require('../utils/BindVertexArray'); |
| 2 | +var CreateProgram = require('../utils/CreateProgram'); |
| 3 | +var CreateShader = require('../utils/CreateShader'); |
| 4 | +var CreateBuffer = require('../utils/CreateBuffer'); |
| 5 | +var CreateAttribDesc = require('../utils/CreateAttribDesc'); |
| 6 | +var VertexBuffer = require('../utils/VertexBuffer'); |
| 7 | +var IndexBuffer = require('../utils/IndexBuffer'); |
| 8 | +var VertexArray = require('../utils/VertexArray'); |
| 9 | +var CONST = require('../../const'); |
| 10 | + |
| 11 | +var ParticleRenderer = function () |
| 12 | +{ |
| 13 | + this.glContext = null; |
| 14 | + this.maxParticles = null; |
| 15 | + this.vertShader = null; |
| 16 | + this.fragShader = null; |
| 17 | + this.program = null; |
| 18 | + this.vertexArray = null; |
| 19 | + this.indexBufferObject = null; |
| 20 | + this.vertexDataBuffer = null; |
| 21 | + this.indexDataBuffer = null; |
| 22 | + this.elementCount = 0; |
| 23 | + this.currentTexture2D = null; |
| 24 | + this.viewMatrixLocation = null; |
| 25 | + this.type = CONST.WEBGL; |
| 26 | + this.view = game.canvas; |
| 27 | + this.resolution = game.config.resolution; |
| 28 | + this.init(); |
| 29 | +}; |
| 30 | + |
| 31 | +// VERTEX_SIZE = sizeof(vec2) + sizeof(vec2) |
| 32 | +ParticleRenderer.VERTEX_SIZE = 16; |
| 33 | +ParticleRenderer.INDEX_SIZE = 2; |
| 34 | +ParticleRenderer.PARTICLE_VERTEX_COUNT = 4; |
| 35 | +ParticleRenderer.PARTICLE_INDEX_COUNT = 6; |
| 36 | + |
| 37 | +// How many 32-bit components does the vertex have. |
| 38 | +ParticleRenderer.PARTICLE_VERTEX_COMPONENT_COUNT = 4; |
| 39 | + |
| 40 | +// Can't be bigger since index are 16-bit |
| 41 | +ParticleRenderer.MAX_PARTICLES = 10000; |
| 42 | +ParticleRenderer.VERTEX_SHADER_SOURCE = [ |
| 43 | + 'uniform mat4 u_view_matrix;', |
| 44 | + 'attribute vec2 a_position;', |
| 45 | + 'attribute vec2 a_tex_coord;', |
| 46 | + 'varying vec2 v_tex_coord;', |
| 47 | + 'void main () {', |
| 48 | + ' gl_Position = u_view_matrix * vec4(a_position, 1.0, 1.0);', |
| 49 | + ' v_tex_coord = a_tex_coord;', |
| 50 | + '}' |
| 51 | +].join('\n'); |
| 52 | +ParticleRenderer.FRAGMENT_SHADER_SOURCE = [ |
| 53 | + 'precision lowp float;', |
| 54 | + 'uniform sampler2D u_sampler2D;', |
| 55 | + 'varying vec2 v_tex_coord;', |
| 56 | + 'void main() {', |
| 57 | + ' gl_FragColor = texture2D(u_sampler2D, v_tex_coord);', |
| 58 | + '}' |
| 59 | +].join('\n'); |
| 60 | + |
| 61 | +ParticleRenderer.prototype.init = function () |
| 62 | +{ |
| 63 | + if (this.glContext === null) |
| 64 | + { |
| 65 | + var gl = this.view.getContext('webgl', this.config.WebGLContextOptions) || this.view.getContext('experimental-webgl', this.config.WebGLContextOptions); |
| 66 | + var vertexDataBuffer = new VertexBuffer(ParticleRenderer.VERTEX_SIZE * ParticleRenderer.PARTICLE_VERTEX_COUNT * ParticleRenderer.MAX_PARTICLES); |
| 67 | + var indexDataBuffer = new IndexBuffer(ParticleRenderer.INDEX_SIZE * ParticleRenderer.PARTICLE_INDEX_COUNT * ParticleRenderer.MAX_PARTICLES); |
| 68 | + var vertShader = CreateShader(gl, ParticleRenderer.VERTEX_SHADER_SOURCE, gl.VERTEX_SHADER); |
| 69 | + var fragShader = CreateShader(gl, ParticleRenderer.FRAGMENT_SHADER_SOURCE, gl.FRAGMENT_SHADER_SOURCE); |
| 70 | + var program = CreateProgram(gl, vertShader, fragShader); |
| 71 | + var indexBufferObject = CreateBuffer(gl, gl.ELEMENT_ARRAY_BUFFER, gl.STATIC_DRAW, null, indexDataBuffer.getByteCapacity()); |
| 72 | + var vertexArray = new VertexArray(gl, |
| 73 | + CreateBuffer(gl, gl.ARRAY_BUFFER, gl.STREAM_DRAW, null, vertexDataBuffer.getByteCapacity()), |
| 74 | + [ |
| 75 | + CreateAttributeDesc(gl, program, 'a_position', 2, gl.FLOAT, false, ParticleRendererRenderer.VERTEX_SIZE, 0), |
| 76 | + CreateAttributeDesc(gl, program, 'a_tex_coord', 2, gl.FLOAT, false, ParticleRendererRenderer.VERTEX_SIZE, 8) |
| 77 | + ] |
| 78 | + ); |
| 79 | + var viewMatrixLocation = gl.getUniformLocation(program, 'u_view_matrix'); |
| 80 | + var view = this.view; |
| 81 | + this.vertexDataBuffer = vertexDataBuffer; |
| 82 | + this.indexDataBuffer = indexDataBuffer; |
| 83 | + this.vertShader = vertShader; |
| 84 | + this.fragShader = fragShader; |
| 85 | + this.program = program; |
| 86 | + this.indexBufferObject = indexBufferObject; |
| 87 | + this.vertexArray = vertexArray; |
| 88 | + this.glContext = gl; |
| 89 | + gl.uniformMatrix4fv( |
| 90 | + viewMatrixLocation, |
| 91 | + false, |
| 92 | + new Float32Array([ |
| 93 | + 2 / view.width, 0, 0, 0, |
| 94 | + 0, -2 / view.height, 0, 0, |
| 95 | + 0, 0, 1, 1, |
| 96 | + -1, 1, 0, 0 |
| 97 | + ]) |
| 98 | + ); |
| 99 | + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBufferObject); |
| 100 | + var indexBuffer = indexDataBuffer.wordView; |
| 101 | + for (var indexA = indexB = 0; |
| 102 | + indexA < ParticleRenderer.MAX_PARTICLES * ParticleRenderer.PARTICLE_INDEX_COUNT; |
| 103 | + indexA += ParticleRenderer.PARTICLE_INDEX_COUNT, indexB += ParticleRenderer.PARTICLE_VERTEX_COUNT) |
| 104 | + { |
| 105 | + indexBuffer[indexA + 0] = indexB + 0; |
| 106 | + indexBuffer[indexA + 1] = indexB + 1; |
| 107 | + indexBuffer[indexA + 2] = indexB + 2; |
| 108 | + indexBuffer[indexA + 3] = indexB + 0; |
| 109 | + indexBuffer[indexA + 4] = indexB + 2; |
| 110 | + indexBuffer[indexA + 5] = indexB + 3; |
| 111 | + } |
| 112 | + } |
| 113 | + else |
| 114 | + { |
| 115 | + console.error('ParticleRenderer already initialized'); |
| 116 | + } |
| 117 | +}; |
| 118 | + |
| 119 | +ParticleRenderer.prototype.destroy = function () |
| 120 | +{ |
| 121 | + var gl = this.glContext; |
| 122 | + if (gl) |
| 123 | + { |
| 124 | + gl.deleteShader(this.vertShader); |
| 125 | + gl.deleteShader(this.fragShader); |
| 126 | + gl.deleteProgram(this.program); |
| 127 | + gl.deleteBuffer(this.indexBufferObject); |
| 128 | + gl.deleteBuffer(this.vertexArray.buffer); |
| 129 | + } |
| 130 | +}; |
| 131 | + |
| 132 | +ParticleRenderer.prototype.isFull = function () |
| 133 | +{ |
| 134 | + var vertexDataBuffer = this.vertexDataBuffer; |
| 135 | + return (vertexDataBuffer.getByteLength() >= vertexDataBuffer.getByteCapacity()); |
| 136 | +}; |
| 137 | + |
| 138 | +ParticleRenderer.prototype.add = function (x, y, width, height, umin, vmin, umax, vmax) |
| 139 | +{ |
| 140 | + // The user must check if the buffers are full before flushing |
| 141 | + // this is to give freedom of when should the renderer flush. |
| 142 | + var vertexDataBuffer = this.vertexDataBuffer; |
| 143 | + var indexDataBuffer = this.indexDataBuffer; |
| 144 | + var vertexBuffer = vertexDataBuffer.floatView; |
| 145 | + var vertexOffset = vertexDataBuffer.allocate(ParticleRenderer.PARTICLE_VERTEX_COMPONENT_COUNT * ParticleRenderer.PARTICLE_VERTEX_COUNT); |
| 146 | + |
| 147 | + vertexBuffer[vertexOffset++] = x; |
| 148 | + vertexBuffer[vertexOffset++] = y; |
| 149 | + vertexBuffer[vertexOffset++] = umin; |
| 150 | + vertexBuffer[vertexOffset++] = vmin; |
| 151 | + |
| 152 | + vertexBuffer[vertexOffset++] = x; |
| 153 | + vertexBuffer[vertexOffset++] = y + height; |
| 154 | + vertexBuffer[vertexOffset++] = umin; |
| 155 | + vertexBuffer[vertexOffset++] = vmax; |
| 156 | + |
| 157 | + vertexBuffer[vertexOffset++] = x + width; |
| 158 | + vertexBuffer[vertexOffset++] = y + height; |
| 159 | + vertexBuffer[vertexOffset++] = umax; |
| 160 | + vertexBuffer[vertexOffset++] = vmax; |
| 161 | + |
| 162 | + vertexBuffer[vertexOffset++] = x + width; |
| 163 | + vertexBuffer[vertexOffset++] = y; |
| 164 | + vertexBuffer[vertexOffset++] = umax; |
| 165 | + vertexBuffer[vertexOffset++] = vmin; |
| 166 | + |
| 167 | + this.elementCount += ParticleRenderer.PARTICLE_INDEX_COUNT; |
| 168 | +}; |
| 169 | + |
| 170 | +ParticleRenderer.prototype.setTexture2D = function (texture2D) |
| 171 | +{ |
| 172 | + var gl = this.glContext; |
| 173 | + if (this.currentTexture2D != texture2D) |
| 174 | + { |
| 175 | + this.flush(); |
| 176 | + gl.activeTexture(gl.TEXTURE0); |
| 177 | + gl.bindTexture(gl.TEXTURE_2D, texture2D); |
| 178 | + } |
| 179 | +}; |
| 180 | + |
| 181 | +ParticleRenderer.prototype.bind = function () |
| 182 | +{ |
| 183 | + var gl = this.glContext; |
| 184 | + gl.clearColor(0, 0, 0, 1); |
| 185 | + gl.enable(gl.BLEND); |
| 186 | + gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA); |
| 187 | + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBufferObject); |
| 188 | + BindVertexArray(this.vertexArray); |
| 189 | +}; |
| 190 | + |
| 191 | +ParticleRenderer.prototype.unbind = function () |
| 192 | +{ |
| 193 | + var gl = this.glContext; |
| 194 | + gl.disable(gl.BLEND); |
| 195 | + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null); |
| 196 | + gl.bindBuffer(gl.ARRAY_BUFFER, null); |
| 197 | +}; |
| 198 | + |
| 199 | +ParticleRenderer.prototype.flush = function () |
| 200 | +{ |
| 201 | + var gl = this.glContext; |
| 202 | + var vertexDataBuffer = this.vertexDataBuffer; |
| 203 | + gl.bufferSubData(gl.ARRAY_BUFFER, 0, vertexDataBuffer.getUsedBufferAsFloat()); |
| 204 | + gl.drawElements(gl.TRIANGLES, this.elementCount, gl.UNSIGNED_SHORT, 0); |
| 205 | + vertexDataBuffer.clear(); |
| 206 | + this.elementCount = 0; |
| 207 | +}; |
| 208 | + |
| 209 | +ParticleRenderer.prototype.resize = function (width, height) |
| 210 | +{}; |
| 211 | + |
| 212 | +module.exports = ParticleRenderer; |
0 commit comments