UNPKG

gl-image

Version:
144 lines (143 loc) 6.31 kB
"use strict"; function polyfill() { // From: https://github.com/evanw/OES_texture_float_linear-polyfill // Uploads a 2x2 floating-point texture where one pixel is 2 and the other // three pixels are 0. Linear filtering is only supported if a sample taken // from the center of that texture is (2 + 0 + 0 + 0) / 4 = 0.5. function supportsOESTextureFloatLinear(gl) { // Need floating point textures in the first place if (!gl.getExtension('OES_texture_float')) { return false; } // Create a render target var framebuffer = gl.createFramebuffer(); var byteTexture = gl.createTexture(); gl.bindTexture(gl.TEXTURE_2D, byteTexture); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer); gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, byteTexture, 0); // Create a simple floating-point texture with value of 0.5 in the center var rgba = [ 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]; var floatTexture = gl.createTexture(); gl.bindTexture(gl.TEXTURE_2D, floatTexture); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 2, 2, 0, gl.RGBA, gl.FLOAT, new Float32Array(rgba)); // Create the test shader var program = gl.createProgram(); var vertexShader = gl.createShader(gl.VERTEX_SHADER); var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER); if (!program || !vertexShader || !fragmentShader) { throw new Error('failed to create webgl program.'); } gl.shaderSource(vertexShader, '\ attribute vec2 vertex;\ void main() {\ gl_Position = vec4(vertex, 0.0, 1.0);\ }\ '); gl.shaderSource(fragmentShader, '\ uniform sampler2D texture;\ void main() {\ gl_FragColor = texture2D(texture, vec2(0.5));\ }\ '); gl.compileShader(vertexShader); gl.compileShader(fragmentShader); gl.attachShader(program, vertexShader); gl.attachShader(program, fragmentShader); gl.linkProgram(program); // Create a buffer containing a single point var buffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, buffer); gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([0, 0]), gl.STREAM_DRAW); gl.enableVertexAttribArray(0); gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0); // Render the point and read back the rendered pixel var pixel = new Uint8Array(4); gl.useProgram(program); gl.viewport(0, 0, 1, 1); gl.bindTexture(gl.TEXTURE_2D, floatTexture); gl.drawArrays(gl.POINTS, 0, 1); gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixel); // The center sample will only have a value of 0.5 if linear filtering works return pixel[0] === 127 || pixel[0] === 128; } // The constructor for the returned extension object var OESTextureFloatLinear = /** @class */ (function () { function OESTextureFloatLinear() { } return OESTextureFloatLinear; }()); // Cache the extension so it's specific to each context like extensions should be function getOESTextureFloatLinear(gl) { if (gl.$OES_texture_float_linear$ === void 0) { Object.defineProperty(gl, '$OES_texture_float_linear$', { enumerable: false, configurable: false, writable: false, value: new OESTextureFloatLinear() }); } return gl.$OES_texture_float_linear$; } // This replaces the real getExtension() function getExtension(name) { if (!(this instanceof WebGLRenderingContext)) { throw new Error('getExtension must be called by webgl context!'); } return name === 'OES_texture_float_linear' ? getOESTextureFloatLinear(this) : oldGetExtension.call(this, name); } // This replaces the real getSupportedExtensions() function getSupportedExtensions() { if (!(this instanceof WebGLRenderingContext)) { throw new Error('getSupportedExtensions must be called by webgl context!'); } var extensions = oldGetSupportedExtensions.call(this); if (extensions.indexOf('OES_texture_float_linear') === -1) { extensions.push('OES_texture_float_linear'); } return extensions; } // Get a WebGL context var oldGetExtension; var oldGetSupportedExtensions; var gl; try { var canvas = document.createElement('canvas'); gl = (canvas.getContext('webgl') || canvas.getContext('experimental-webgl')); } catch (e) { throw e; } if (!gl) { return; } // Don't install the polyfill if the browser already supports it or doesn't have WebGL var oldExtensions = gl.getSupportedExtensions(); if (Array.isArray(oldExtensions) && oldExtensions.indexOf('OES_texture_float_linear') !== -1) { return; } // Install the polyfill if linear filtering works with floating-point textures if (supportsOESTextureFloatLinear(gl)) { oldGetExtension = WebGLRenderingContext.prototype.getExtension; oldGetSupportedExtensions = WebGLRenderingContext.prototype.getSupportedExtensions; WebGLRenderingContext.prototype.getExtension = getExtension; WebGLRenderingContext.prototype.getSupportedExtensions = getSupportedExtensions; } } polyfill();