UNPKG

phaser

Version:

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

129 lines (99 loc) 4.4 kB
/** * @author Richard Davey <rich@phaser.io> * @copyright 2013-2026 Phaser Studio Inc. * @license {@link https://opensource.org/licenses/MIT|MIT License} */ var CanvasPool = require('../../display/canvas/CanvasPool'); var Color = require('../../display/color/Color'); var GetFastValue = require('../../utils/object/GetFastValue'); /** * Takes a snapshot of an area from the current frame displayed by a WebGL canvas, * or reads the color value of a single pixel, depending on the `getPixel` property * of the snapshot configuration object. * * When capturing an area, the raw pixel data is read from the WebGL context and * composited into a temporary canvas, accounting for WebGL's inverted Y-axis and * optionally reversing pre-multiplied alpha. The canvas is then serialized to a * data URL and loaded into an Image object, which is passed to the callback defined * in the Snapshot Configuration object once loading completes. * * When reading a single pixel, the RGBA values at the given coordinates are read * directly via `gl.readPixels` and returned as a `Phaser.Display.Color` object * via the callback. * * @function Phaser.Renderer.Snapshot.WebGL * @since 3.0.0 * * @param {WebGLRenderingContext} sourceContext - The WebGL context to take a snapshot of. * @param {Phaser.Types.Renderer.Snapshot.SnapshotState} config - The snapshot configuration object. */ var WebGLSnapshot = function (sourceContext, config) { var gl = sourceContext; var callback = GetFastValue(config, 'callback'); var type = GetFastValue(config, 'type', 'image/png'); var encoderOptions = GetFastValue(config, 'encoder', 0.92); var x = Math.abs(Math.round(GetFastValue(config, 'x', 0))); var y = Math.abs(Math.round(GetFastValue(config, 'y', 0))); var getPixel = GetFastValue(config, 'getPixel', false); var isFramebuffer = GetFastValue(config, 'isFramebuffer', false); var bufferWidth = (isFramebuffer) ? GetFastValue(config, 'bufferWidth', 1) : gl.drawingBufferWidth; var bufferHeight = (isFramebuffer) ? GetFastValue(config, 'bufferHeight', 1) : gl.drawingBufferHeight; if (getPixel) { var pixel = new Uint8Array(4); var destY = bufferHeight - y - 1; gl.readPixels(x, destY, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixel); callback.call(null, new Color(pixel[0], pixel[1], pixel[2], pixel[3])); } else { var width = Math.floor(GetFastValue(config, 'width', bufferWidth)); var height = Math.floor(GetFastValue(config, 'height', bufferHeight)); var total = width * height * 4; var pixels = new Uint8Array(total); gl.readPixels(x, bufferHeight - y - height, width, height, gl.RGBA, gl.UNSIGNED_BYTE, pixels); var canvas = CanvasPool.createWebGL(this, width, height); var ctx = canvas.getContext('2d', { willReadFrequently: true }); var imageData = ctx.getImageData(0, 0, width, height); var data = imageData.data; for (var py = 0; py < height; py++) { for (var px = 0; px < width; px++) { var sourceIndex = ((height - py - 1) * width + px) * 4; var destIndex = (py * width + px) * 4; var r = pixels[sourceIndex + 0]; var g = pixels[sourceIndex + 1]; var b = pixels[sourceIndex + 2]; var a = pixels[sourceIndex + 3]; // Un-premultiplication. if (config.unpremultiplyAlpha && a !== 0) { var ratio = 255 / a; r = Math.floor(r * ratio); g = Math.floor(g * ratio); b = Math.floor(b * ratio); } data[destIndex + 0] = r; data[destIndex + 1] = g; data[destIndex + 2] = b; data[destIndex + 3] = a; } } ctx.putImageData(imageData, 0, 0); var image = new Image(); image.onerror = function () { callback.call(null); CanvasPool.remove(canvas); }; image.onload = function () { callback.call(null, image); CanvasPool.remove(canvas); }; image.src = canvas.toDataURL(type, encoderOptions); } }; module.exports = WebGLSnapshot;