UNPKG

@azerion/phaser

Version:

A fast, free and fun HTML5 Game Framework for Desktop and Mobile web browsers.

648 lines (503 loc) 17.9 kB
/** * @author Mat Groves http://matgroves.com/ */ /** * * @class Strip * @extends DisplayObjectContainer * @constructor * @param texture {Texture} The texture to use * @param width {Number} the width * @param height {Number} the height * */ PIXI.Strip = function(texture) { PIXI.DisplayObjectContainer.call( this ); /** * The texture of the strip * * @property texture * @type Texture */ this.texture = texture; // set up the main bits.. this.uvs = new PIXI.Float32Array([0, 1, 1, 1, 1, 0, 0, 1]); this.vertices = new PIXI.Float32Array([0, 0, 100, 0, 100, 100, 0, 100]); this.colors = new PIXI.Float32Array([1, 1, 1, 1]); this.indices = new PIXI.Uint16Array([0, 1, 2, 3]); /** * Whether the strip is dirty or not * * @property dirty * @type Boolean */ this.dirty = true; /** * The blend mode to be applied to the sprite. Set to PIXI.blendModes.NORMAL to remove any blend mode. * * @property blendMode * @type Number * @default PIXI.blendModes.NORMAL; */ this.blendMode = PIXI.blendModes.NORMAL; /** * Triangles in canvas mode are automatically antialiased, use this value to force triangles to overlap a bit with each other. * * @property canvasPadding * @type Number */ this.canvasPadding = 0; this.drawMode = PIXI.Strip.DrawModes.TRIANGLE_STRIP; }; // constructor PIXI.Strip.prototype = Object.create(PIXI.DisplayObjectContainer.prototype); PIXI.Strip.prototype.constructor = PIXI.Strip; PIXI.Strip.prototype._renderWebGL = function(renderSession) { // if the sprite is not visible or the alpha is 0 then no need to render this element if(!this.visible || this.alpha <= 0)return; // render triangle strip.. renderSession.spriteBatch.stop(); // init! init! if(!this._vertexBuffer)this._initWebGL(renderSession); renderSession.shaderManager.setShader(renderSession.shaderManager.stripShader); this._renderStrip(renderSession); ///renderSession.shaderManager.activateDefaultShader(); renderSession.spriteBatch.start(); //TODO check culling }; PIXI.Strip.prototype._initWebGL = function(renderSession) { // build the strip! var gl = renderSession.gl; this._vertexBuffer = gl.createBuffer(); this._indexBuffer = gl.createBuffer(); this._uvBuffer = gl.createBuffer(); this._colorBuffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, this._vertexBuffer); gl.bufferData(gl.ARRAY_BUFFER, this.vertices, gl.DYNAMIC_DRAW); gl.bindBuffer(gl.ARRAY_BUFFER, this._uvBuffer); gl.bufferData(gl.ARRAY_BUFFER, this.uvs, gl.STATIC_DRAW); gl.bindBuffer(gl.ARRAY_BUFFER, this._colorBuffer); gl.bufferData(gl.ARRAY_BUFFER, this.colors, gl.STATIC_DRAW); gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._indexBuffer); gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, this.indices, gl.STATIC_DRAW); }; PIXI.Strip.prototype._renderStrip = function(renderSession) { var gl = renderSession.gl; var projection = renderSession.projection, offset = renderSession.offset, shader = renderSession.shaderManager.stripShader; var drawMode = this.drawMode === PIXI.Strip.DrawModes.TRIANGLE_STRIP ? gl.TRIANGLE_STRIP : gl.TRIANGLES; // gl.uniformMatrix4fv(shaderProgram.mvMatrixUniform, false, mat4Real); renderSession.blendModeManager.setBlendMode(this.blendMode); // set uniforms gl.uniformMatrix3fv(shader.translationMatrix, false, this.worldTransform.toArray(true)); gl.uniform2f(shader.projectionVector, projection.x, -projection.y); gl.uniform2f(shader.offsetVector, -offset.x, -offset.y); gl.uniform1f(shader.alpha, this.worldAlpha); if(!this.dirty) { gl.bindBuffer(gl.ARRAY_BUFFER, this._vertexBuffer); gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.vertices); gl.vertexAttribPointer(shader.aVertexPosition, 2, gl.FLOAT, false, 0, 0); // update the uvs gl.bindBuffer(gl.ARRAY_BUFFER, this._uvBuffer); gl.vertexAttribPointer(shader.aTextureCoord, 2, gl.FLOAT, false, 0, 0); gl.activeTexture(gl.TEXTURE0); // check if a texture is dirty.. if(this.texture.baseTexture._dirty[gl.id]) { renderSession.renderer.updateTexture(this.texture.baseTexture); } else { // bind the current texture gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id]); } // dont need to upload! gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._indexBuffer); } else { this.dirty = false; gl.bindBuffer(gl.ARRAY_BUFFER, this._vertexBuffer); gl.bufferData(gl.ARRAY_BUFFER, this.vertices, gl.STATIC_DRAW); gl.vertexAttribPointer(shader.aVertexPosition, 2, gl.FLOAT, false, 0, 0); // update the uvs gl.bindBuffer(gl.ARRAY_BUFFER, this._uvBuffer); gl.bufferData(gl.ARRAY_BUFFER, this.uvs, gl.STATIC_DRAW); gl.vertexAttribPointer(shader.aTextureCoord, 2, gl.FLOAT, false, 0, 0); gl.activeTexture(gl.TEXTURE0); // check if a texture is dirty.. if(this.texture.baseTexture._dirty[gl.id]) { renderSession.renderer.updateTexture(this.texture.baseTexture); } else { gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id]); } // dont need to upload! gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._indexBuffer); gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, this.indices, gl.STATIC_DRAW); } //console.log(gl.TRIANGLE_STRIP) // // gl.drawElements(drawMode, this.indices.length, gl.UNSIGNED_SHORT, 0); }; PIXI.Strip.prototype._renderCanvas = function(renderSession) { var context = renderSession.context; var transform = this.worldTransform; var tx = (transform.tx * renderSession.resolution) + renderSession.shakeX; var ty = (transform.ty * renderSession.resolution) + renderSession.shakeY; if (renderSession.roundPixels) { context.setTransform(transform.a, transform.b, transform.c, transform.d, tx | 0, ty | 0); } else { context.setTransform(transform.a, transform.b, transform.c, transform.d, tx, ty); } if (this.drawMode === PIXI.Strip.DrawModes.TRIANGLE_STRIP) { this._renderCanvasTriangleStrip(context); } else { this._renderCanvasTriangles(context); } }; PIXI.Strip.prototype._renderCanvasTriangleStrip = function(context) { // draw triangles!! var vertices = this.vertices; var uvs = this.uvs; var length = vertices.length / 2; this.count++; for (var i = 0; i < length - 2; i++) { // draw some triangles! var index = i * 2; this._renderCanvasDrawTriangle(context, vertices, uvs, index, (index + 2), (index + 4)); } }; PIXI.Strip.prototype._renderCanvasTriangles = function(context) { // draw triangles!! var vertices = this.vertices; var uvs = this.uvs; var indices = this.indices; var length = indices.length; this.count++; for (var i = 0; i < length; i += 3) { // draw some triangles! var index0 = indices[i] * 2, index1 = indices[i + 1] * 2, index2 = indices[i + 2] * 2; this._renderCanvasDrawTriangle(context, vertices, uvs, index0, index1, index2); } }; PIXI.Strip.prototype._renderCanvasDrawTriangle = function(context, vertices, uvs, index0, index1, index2) { var textureSource = this.texture.baseTexture.source; var textureWidth = this.texture.width; var textureHeight = this.texture.height; var x0 = vertices[index0], x1 = vertices[index1], x2 = vertices[index2]; var y0 = vertices[index0 + 1], y1 = vertices[index1 + 1], y2 = vertices[index2 + 1]; var u0 = uvs[index0] * textureWidth, u1 = uvs[index1] * textureWidth, u2 = uvs[index2] * textureWidth; var v0 = uvs[index0 + 1] * textureHeight, v1 = uvs[index1 + 1] * textureHeight, v2 = uvs[index2 + 1] * textureHeight; if (this.canvasPadding > 0) { var paddingX = this.canvasPadding / this.worldTransform.a; var paddingY = this.canvasPadding / this.worldTransform.d; var centerX = (x0 + x1 + x2) / 3; var centerY = (y0 + y1 + y2) / 3; var normX = x0 - centerX; var normY = y0 - centerY; var dist = Math.sqrt(normX * normX + normY * normY); x0 = centerX + (normX / dist) * (dist + paddingX); y0 = centerY + (normY / dist) * (dist + paddingY); // normX = x1 - centerX; normY = y1 - centerY; dist = Math.sqrt(normX * normX + normY * normY); x1 = centerX + (normX / dist) * (dist + paddingX); y1 = centerY + (normY / dist) * (dist + paddingY); normX = x2 - centerX; normY = y2 - centerY; dist = Math.sqrt(normX * normX + normY * normY); x2 = centerX + (normX / dist) * (dist + paddingX); y2 = centerY + (normY / dist) * (dist + paddingY); } context.save(); context.beginPath(); context.moveTo(x0, y0); context.lineTo(x1, y1); context.lineTo(x2, y2); context.closePath(); context.clip(); // Compute matrix transform var delta = (u0 * v1) + (v0 * u2) + (u1 * v2) - (v1 * u2) - (v0 * u1) - (u0 * v2); var deltaA = (x0 * v1) + (v0 * x2) + (x1 * v2) - (v1 * x2) - (v0 * x1) - (x0 * v2); var deltaB = (u0 * x1) + (x0 * u2) + (u1 * x2) - (x1 * u2) - (x0 * u1) - (u0 * x2); var deltaC = (u0 * v1 * x2) + (v0 * x1 * u2) + (x0 * u1 * v2) - (x0 * v1 * u2) - (v0 * u1 * x2) - (u0 * x1 * v2); var deltaD = (y0 * v1) + (v0 * y2) + (y1 * v2) - (v1 * y2) - (v0 * y1) - (y0 * v2); var deltaE = (u0 * y1) + (y0 * u2) + (u1 * y2) - (y1 * u2) - (y0 * u1) - (u0 * y2); var deltaF = (u0 * v1 * y2) + (v0 * y1 * u2) + (y0 * u1 * v2) - (y0 * v1 * u2) - (v0 * u1 * y2) - (u0 * y1 * v2); context.transform(deltaA / delta, deltaD / delta, deltaB / delta, deltaE / delta, deltaC / delta, deltaF / delta); context.drawImage(textureSource, 0, 0); context.restore(); }; /** * Renders a flat strip * * @method renderStripFlat * @param strip {Strip} The Strip to render * @private */ PIXI.Strip.prototype.renderStripFlat = function(strip) { var context = this.context; var vertices = strip.vertices; var length = vertices.length/2; this.count++; context.beginPath(); for (var i=1; i < length-2; i++) { // draw some triangles! var index = i*2; var x0 = vertices[index], x1 = vertices[index+2], x2 = vertices[index+4]; var y0 = vertices[index+1], y1 = vertices[index+3], y2 = vertices[index+5]; context.moveTo(x0, y0); context.lineTo(x1, y1); context.lineTo(x2, y2); } context.fillStyle = '#FF0000'; context.fill(); context.closePath(); }; /* PIXI.Strip.prototype.setTexture = function(texture) { //TODO SET THE TEXTURES //TODO VISIBILITY // stop current texture this.texture = texture; this.width = texture.frame.width; this.height = texture.frame.height; this.updateFrame = true; }; */ /** * When the texture is updated, this event will fire to update the scale and frame * * @method onTextureUpdate * @param event * @private */ PIXI.Strip.prototype.onTextureUpdate = function() { this.updateFrame = true; }; /** * Returns the bounds of the mesh as a rectangle. The bounds calculation takes the worldTransform into account. * * @method getBounds * @param matrix {Matrix} the transformation matrix of the sprite * @return {Rectangle} the framing rectangle */ PIXI.Strip.prototype.getBounds = function(matrix) { var worldTransform = matrix || this.worldTransform; var a = worldTransform.a; var b = worldTransform.b; var c = worldTransform.c; var d = worldTransform.d; var tx = worldTransform.tx; var ty = worldTransform.ty; var maxX = -Infinity; var maxY = -Infinity; var minX = Infinity; var minY = Infinity; var vertices = this.vertices; for (var i = 0, n = vertices.length; i < n; i += 2) { var rawX = vertices[i], rawY = vertices[i + 1]; var x = (a * rawX) + (c * rawY) + tx; var y = (d * rawY) + (b * rawX) + ty; minX = x < minX ? x : minX; minY = y < minY ? y : minY; maxX = x > maxX ? x : maxX; maxY = y > maxY ? y : maxY; } if (minX === -Infinity || maxY === Infinity) { return PIXI.EmptyRectangle; } var bounds = this._bounds; bounds.x = minX; bounds.width = maxX - minX; bounds.y = minY; bounds.height = maxY - minY; // store a reference so that if this function gets called again in the render cycle we do not have to recalculate this._currentBounds = bounds; return bounds; }; /** * Different drawing buffer modes supported * * @property * @type {{TRIANGLE_STRIP: number, TRIANGLES: number}} * @static */ PIXI.Strip.DrawModes = { TRIANGLE_STRIP: 0, TRIANGLES: 1 }; /** * @author Mat Groves http://matgroves.com/ @Doormat23 * @copyright Mat Groves, Rovanion Luckey */ /** * * @class Rope * @constructor * @extends Strip * @param {Texture} texture - The texture to use on the rope. * @param {Array} points - An array of {PIXI.Point}. * */ PIXI.Rope = function(texture, points) { PIXI.Strip.call( this, texture ); this.points = points; this.vertices = new PIXI.Float32Array(points.length * 4); this.uvs = new PIXI.Float32Array(points.length * 4); this.colors = new PIXI.Float32Array(points.length * 2); this.indices = new PIXI.Uint16Array(points.length * 2); this.refresh(); }; // constructor PIXI.Rope.prototype = Object.create( PIXI.Strip.prototype ); PIXI.Rope.prototype.constructor = PIXI.Rope; /* * Refreshes * * @method refresh */ PIXI.Rope.prototype.refresh = function() { var points = this.points; if(points.length < 1) return; var uvs = this.uvs; var lastPoint = points[0]; var indices = this.indices; var colors = this.colors; this.count-=0.2; uvs[0] = 0; uvs[1] = 0; uvs[2] = 0; uvs[3] = 1; colors[0] = 1; colors[1] = 1; indices[0] = 0; indices[1] = 1; var total = points.length, point, index, amount; for (var i = 1; i < total; i++) { point = points[i]; index = i * 4; // time to do some smart drawing! amount = i / (total-1); if(i%2) { uvs[index] = amount; uvs[index+1] = 0; uvs[index+2] = amount; uvs[index+3] = 1; } else { uvs[index] = amount; uvs[index+1] = 0; uvs[index+2] = amount; uvs[index+3] = 1; } index = i * 2; colors[index] = 1; colors[index+1] = 1; index = i * 2; indices[index] = index; indices[index + 1] = index + 1; lastPoint = point; } }; /* * Updates the object transform for rendering * * @method updateTransform * @private */ PIXI.Rope.prototype.updateTransform = function() { var points = this.points; if(points.length < 1)return; var lastPoint = points[0]; var nextPoint; var perp = {x:0, y:0}; this.count-=0.2; var vertices = this.vertices; var total = points.length, point, index, ratio, perpLength, num; for (var i = 0; i < total; i++) { point = points[i]; index = i * 4; if(i < points.length-1) { nextPoint = points[i+1]; } else { nextPoint = point; } perp.y = -(nextPoint.x - lastPoint.x); perp.x = nextPoint.y - lastPoint.y; ratio = (1 - (i / (total-1))) * 10; if(ratio > 1) ratio = 1; perpLength = Math.sqrt(perp.x * perp.x + perp.y * perp.y); num = this.texture.height / 2; //(20 + Math.abs(Math.sin((i + this.count) * 0.3) * 50) )* ratio; perp.x /= perpLength; perp.y /= perpLength; perp.x *= num; perp.y *= num; vertices[index] = point.x + perp.x; vertices[index+1] = point.y + perp.y; vertices[index+2] = point.x - perp.x; vertices[index+3] = point.y - perp.y; lastPoint = point; } PIXI.DisplayObjectContainer.prototype.updateTransform.call( this ); }; /* * Sets the texture that the Rope will use * * @method setTexture * @param texture {Texture} the texture that will be used */ PIXI.Rope.prototype.setTexture = function(texture) { // stop current texture this.texture = texture; //this.updateFrame = true; };