UNPKG

phaser

Version:

A fast, free and fun HTML5 Game Framework for Desktop and Mobile web browsers from the team at Phaser Studio Inc.

300 lines (268 loc) 11.5 kB
/** * @author Benjamin D. Richards <benjamindrichards@gmail.com> * @copyright 2013-2026 Phaser Studio Inc. * @license {@link https://opensource.org/licenses/MIT|MIT License} */ var Class = require('../../../utils/Class'); var ShaderSourceFS = require('../shaders/Multi-frag'); var ShaderSourceVS = require('../shaders/Multi-vert'); var MakeApplyTint = require('../shaders/additionMakers/MakeApplyTint'); var MakeDefineTexCount = require('../shaders/additionMakers/MakeDefineTexCount'); var MakeGetTexCoordOut = require('../shaders/additionMakers/MakeGetTexCoordOut'); var MakeGetTexRes = require('../shaders/additionMakers/MakeGetTexRes'); var MakeSmoothPixelArt = require('../shaders/additionMakers/MakeSmoothPixelArt'); var MakeGetTexture = require('../shaders/additionMakers/MakeGetTexture'); var Utils = require('../Utils'); var BatchHandlerQuad = require('./BatchHandlerQuad'); var getTint = Utils.getTintAppendFloatAlpha; /** * @classdesc * This RenderNode renders textured triangle strips, such as for the Rope * Game Object. It uses batches to accelerate drawing. * * If a strip is submitted with too many vertices (usually >32,768), * it will throw an error. * * Note that you should call `batchStrip` instead of `batch` to add strips. * * @class BatchHandlerStrip * @memberof Phaser.Renderer.WebGL.RenderNodes * @constructor * @since 4.0.0 * @extends Phaser.Renderer.WebGL.RenderNodes.BatchHandlerQuad * @param {Phaser.Renderer.WebGL.RenderNodes.RenderNodeManager} manager - The manager that owns this RenderNode. * @param {Phaser.Types.Renderer.WebGL.RenderNodes.BatchHandlerConfig} config - The configuration object for this handler. */ var BatchHandlerStrip = new Class({ Extends: BatchHandlerQuad, initialize: function BatchHandlerStrip (manager, config) { BatchHandlerQuad.call(this, manager, config); // We do not expect to use extra textures. this.renderOptions.multiTexturing = true; }, /** * The default configuration object for this handler. * This is merged with the `config` object passed in the constructor. * * @name Phaser.Renderer.WebGL.RenderNodes.BatchHandlerStrip#defaultConfig * @type {Phaser.Types.Renderer.WebGL.RenderNodes.BatchHandlerConfig} * @since 4.0.0 */ defaultConfig: { name: 'BatchHandlerStrip', verticesPerInstance: 2, indicesPerInstance: 2, shaderName: 'STRIP', vertexSource: ShaderSourceVS, fragmentSource: ShaderSourceFS, shaderAdditions: [ MakeGetTexCoordOut(), MakeGetTexRes(true), MakeSmoothPixelArt(true), MakeDefineTexCount(1), MakeGetTexture(), MakeApplyTint() ], vertexBufferLayout: { usage: 'DYNAMIC_DRAW', layout: [ { name: 'inPosition', size: 2 }, { name: 'inTexCoord', size: 2 }, { name: 'inTexDatum' }, { name: 'inTintEffect' }, { name: 'inTint', size: 4, type: 'UNSIGNED_BYTE', normalized: true } ] } }, /** * Generate element indices for the instance vertices. * This is called automatically when the node is initialized. * * By default, each instance is a vertex pair. * Pairs are composed into triangle strips. * Strips in batches are linked by degenerate triangles, * created by repeating the last and first vertices of each strip * in an intermediate pair. * * @method Phaser.Renderer.WebGL.RenderNodes.BatchHandlerStrip#_generateElementIndices * @since 4.0.0 * @private * @param {number} instances - The number of instances to define. * @return {ArrayBuffer} The index buffer data. */ _generateElementIndices: function (instances) { var buffer = new ArrayBuffer(instances * 2 * 2); var indices = new Uint16Array(buffer); var len = indices.length; for (var i = 0; i < len; i++) { indices[i] = i; } return buffer; }, /** * Adds a textured triangle strip to the batch. Each pair of vertices * in `vertices` forms one instance. The vertices are transformed by * `calcMatrix` before being written into the vertex buffer. * * When multiple strips are batched together, degenerate triangles are * automatically inserted between them by repeating the last vertex of * one strip and the first vertex of the next, ensuring correct rendering * without a draw-call break. * * If the incoming strip would overflow the current batch, the batch is * flushed first. If the strip itself exceeds the maximum batch capacity, * an error is thrown. * * This method is named `batchStrip` rather than `batch` because its call * signature differs from the standard batch handlers used by quad-based * Game Objects. * * @method Phaser.Renderer.WebGL.RenderNodes.BatchHandlerStrip#batchStrip * @since 4.0.0 * @param {Phaser.Renderer.WebGL.DrawingContext} drawingContext - The current drawing context. * @param {Phaser.GameObjects.GameObject} src - The Game Object being rendered. * @param {Phaser.GameObjects.Components.TransformMatrix} calcMatrix - The current transform matrix used to transform each vertex position into world space. * @param {Phaser.Renderer.WebGL.Wrappers.WebGLTextureWrapper} glTexture - The texture to render. * @param {Float32Array} vertices - The local-space vertex positions of the strip, as a flat array of alternating x and y values. * @param {Float32Array} uv - The normalized texture coordinates of the strip, as a flat array of alternating u and v values, matching the layout of `vertices`. * @param {Uint32Array} colors - The per-vertex packed tint color values for the strip. * @param {Float32Array} alphas - The per-vertex alpha multiplier values for the strip. * @param {number} alpha - The overall alpha multiplier applied on top of the per-vertex alpha values. * @param {Phaser.TintModes} tintMode - The tint mode to use. * @param {Phaser.Types.Renderer.WebGL.RenderNodes.BatchHandlerQuadRenderOptions} renderOptions - Optional render features. Strip rendering uses a single texture slot and does not support additional multi-texturing. The `smoothPixelArt` option is supported; other options are ignored. * @param {function} [debugCallback] - An optional callback invoked after all vertices are processed, called in the context of `src` with three arguments: the source Game Object, the total vertex count, and a flat array of alternating x,y world-space positions for the transformed vertices. */ batchStrip: function ( drawingContext, src, calcMatrix, glTexture, vertices, uv, colors, alphas, alpha, tintMode, renderOptions, debugCallback ) { if (this.instanceCount === 0) { this.manager.setCurrentBatchNode(this, drawingContext); } var submittedInstanceCount = vertices.length / (2 * this.verticesPerInstance); if (submittedInstanceCount > this.instancesPerBatch) { throw new Error('BatchHandlerStrip: Vertex count exceeds maximum per batch (' + this.maxVerticesPerBatch + ')'); } // Check whether the batch should be rendered immediately. // This guarantees that none of the arrays are full below. if (this.instanceCount + submittedInstanceCount > this.instancesPerBatch) { this.run(drawingContext); // Now the batch is empty. } // Check render options and run the batch if they differ. this.updateRenderOptions(renderOptions); if (this._renderOptionsChanged) { this.run(drawingContext); this.updateShaderConfig(); } // Process textures and get relevant data. var textureDatum = this.batchTextures(glTexture); // Update the vertex buffer. var vertexOffset32 = this.instanceCount * this.floatsPerInstance; var vertexBuffer = this.vertexBufferLayout.buffer; var vertexViewF32 = vertexBuffer.viewF32; var vertexViewU32 = vertexBuffer.viewU32; var repeatFirstVertex = false; // Add degenerate triangles between strips. if (this.instanceCount > 0) { var prevOffset = 1 + this.floatsPerInstance / this.verticesPerInstance; // Copy the previous vertex to the start of the next strip. vertexViewF32[vertexOffset32++] = vertexViewF32[vertexOffset32 - prevOffset]; vertexViewF32[vertexOffset32++] = vertexViewF32[vertexOffset32 - prevOffset]; vertexViewF32[vertexOffset32++] = vertexViewF32[vertexOffset32 - prevOffset]; vertexViewF32[vertexOffset32++] = vertexViewF32[vertexOffset32 - prevOffset]; vertexViewF32[vertexOffset32++] = vertexViewF32[vertexOffset32 - prevOffset]; vertexViewF32[vertexOffset32++] = vertexViewF32[vertexOffset32 - prevOffset]; vertexViewU32[vertexOffset32++] = vertexViewU32[vertexOffset32 - prevOffset]; repeatFirstVertex = true; } var debugVerts; if (debugCallback) { debugVerts = []; } var a = calcMatrix.a; var b = calcMatrix.b; var c = calcMatrix.c; var d = calcMatrix.d; var e = calcMatrix.e; var f = calcMatrix.f; var meshVerticesLength = vertices.length; for (var i = 0; i < meshVerticesLength; i += 2) { var x = vertices[i]; var y = vertices[i + 1]; var tx = x * a + y * c + e; var ty = x * b + y * d + f; vertexViewF32[vertexOffset32++] = tx; vertexViewF32[vertexOffset32++] = ty; vertexViewF32[vertexOffset32++] = uv[i]; vertexViewF32[vertexOffset32++] = uv[i + 1]; vertexViewF32[vertexOffset32++] = textureDatum; vertexViewF32[vertexOffset32++] = tintMode; vertexViewU32[vertexOffset32++] = getTint( colors[i / 2], alphas[i / 2] * alpha ); if (repeatFirstVertex) { // Repeat the first vertex of the strip. i -= 2; // Increment the instance count. this.instanceCount++; this.currentBatchEntry.count++; repeatFirstVertex = false; } else if (debugVerts) { debugVerts.push(tx, ty); } if (i % 4 === 2) { // Every 2 vertices is an instance. // Increment the instance count. this.instanceCount++; this.currentBatchEntry.count++; } } if (debugCallback) { debugCallback.call(src, src, meshVerticesLength, debugVerts); } } }); module.exports = BatchHandlerStrip;