var check = require('./util/check') var isTypedArray = require('./util/is-typed-array') var GL_RGBA = 6408 var GL_UNSIGNED_BYTE = 5121 var GL_PACK_ALIGNMENT = 0x0D05 var GL_FLOAT = 0x1406 // 5126 module.exports = function wrapReadPixels ( gl, framebufferState, reglPoll, context, glAttributes, extensions, limits) { function readPixelsImpl (input) { var type if (framebufferState.next === null) { check( glAttributes.preserveDrawingBuffer, 'you must create a webgl context with "preserveDrawingBuffer":true in order to read pixels from the drawing buffer') type = GL_UNSIGNED_BYTE } else { check( framebufferState.next.colorAttachments[0].texture !== null, 'You cannot read from a renderbuffer') type = framebufferState.next.colorAttachments[0].texture._texture.type check.optional(function () { if (extensions.oes_texture_float) { check( type === GL_UNSIGNED_BYTE || type === GL_FLOAT, 'Reading from a framebuffer is only allowed for the types \'uint8\' and \'float\'') if (type === GL_FLOAT) { check(limits.readFloat, 'Reading \'float\' values is not permitted in your browser. For a fallback, please see: https://www.npmjs.com/package/glsl-read-float') } } else { check( type === GL_UNSIGNED_BYTE, 'Reading from a framebuffer is only allowed for the type \'uint8\'') } }) } var x = 0 var y = 0 var width = context.framebufferWidth var height = context.framebufferHeight var data = null if (isTypedArray(input)) { data = input } else if (input) { check.type(input, 'object', 'invalid arguments to regl.read()') x = input.x | 0 y = input.y | 0 check( x >= 0 && x < context.framebufferWidth, 'invalid x offset for regl.read') check( y >= 0 && y < context.framebufferHeight, 'invalid y offset for regl.read') width = (input.width || (context.framebufferWidth - x)) | 0 height = (input.height || (context.framebufferHeight - y)) | 0 data = input.data || null } // sanity check input.data if (data) { if (type === GL_UNSIGNED_BYTE) { check( data instanceof Uint8Array, 'buffer must be \'Uint8Array\' when reading from a framebuffer of type \'uint8\'') } else if (type === GL_FLOAT) { check( data instanceof Float32Array, 'buffer must be \'Float32Array\' when reading from a framebuffer of type \'float\'') } } check( width > 0 && width + x <= context.framebufferWidth, 'invalid width for read pixels') check( height > 0 && height + y <= context.framebufferHeight, 'invalid height for read pixels') // Update WebGL state reglPoll() // Compute size var size = width * height * 4 // Allocate data if (!data) { if (type === GL_UNSIGNED_BYTE) { data = new Uint8Array(size) } else if (type === GL_FLOAT) { data = data || new Float32Array(size) } } // Type check check.isTypedArray(data, 'data buffer for regl.read() must be a typedarray') check(data.byteLength >= size, 'data buffer for regl.read() too small') // Run read pixels gl.pixelStorei(GL_PACK_ALIGNMENT, 4) gl.readPixels(x, y, width, height, GL_RGBA, type, data) return data } function readPixelsFBO (options) { var result framebufferState.setFBO({ framebuffer: options.framebuffer }, function () { result = readPixelsImpl(options) }) return result } function readPixels (options) { if (!options || !('framebuffer' in options)) { return readPixelsImpl(options) } else { return readPixelsFBO(options) } } return readPixels }