| /** |
| * @licstart The following is the entire license notice for the |
| * Javascript code in this page |
| * |
| * Copyright 2020 Mozilla Foundation |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| * |
| * @licend The above is the entire license notice for the |
| * Javascript code in this page |
| */ |
| "use strict"; |
| |
| Object.defineProperty(exports, "__esModule", { |
| value: true |
| }); |
| exports.WebGLContext = void 0; |
| |
| var _util = require("../shared/util.js"); |
| |
| class WebGLContext { |
| constructor({ |
| enable = false |
| }) { |
| this._enabled = enable === true; |
| } |
| |
| get isEnabled() { |
| let enabled = this._enabled; |
| |
| if (enabled) { |
| enabled = WebGLUtils.tryInitGL(); |
| } |
| |
| return (0, _util.shadow)(this, "isEnabled", enabled); |
| } |
| |
| composeSMask({ |
| layer, |
| mask, |
| properties |
| }) { |
| return WebGLUtils.composeSMask(layer, mask, properties); |
| } |
| |
| drawFigures({ |
| width, |
| height, |
| backgroundColor, |
| figures, |
| context |
| }) { |
| return WebGLUtils.drawFigures(width, height, backgroundColor, figures, context); |
| } |
| |
| clear() { |
| WebGLUtils.cleanup(); |
| } |
| |
| } |
| |
| exports.WebGLContext = WebGLContext; |
| |
| var WebGLUtils = function WebGLUtilsClosure() { |
| function loadShader(gl, code, shaderType) { |
| var shader = gl.createShader(shaderType); |
| gl.shaderSource(shader, code); |
| gl.compileShader(shader); |
| var compiled = gl.getShaderParameter(shader, gl.COMPILE_STATUS); |
| |
| if (!compiled) { |
| var errorMsg = gl.getShaderInfoLog(shader); |
| throw new Error("Error during shader compilation: " + errorMsg); |
| } |
| |
| return shader; |
| } |
| |
| function createVertexShader(gl, code) { |
| return loadShader(gl, code, gl.VERTEX_SHADER); |
| } |
| |
| function createFragmentShader(gl, code) { |
| return loadShader(gl, code, gl.FRAGMENT_SHADER); |
| } |
| |
| function createProgram(gl, shaders) { |
| var program = gl.createProgram(); |
| |
| for (var i = 0, ii = shaders.length; i < ii; ++i) { |
| gl.attachShader(program, shaders[i]); |
| } |
| |
| gl.linkProgram(program); |
| var linked = gl.getProgramParameter(program, gl.LINK_STATUS); |
| |
| if (!linked) { |
| var errorMsg = gl.getProgramInfoLog(program); |
| throw new Error("Error during program linking: " + errorMsg); |
| } |
| |
| return program; |
| } |
| |
| function createTexture(gl, image, textureId) { |
| gl.activeTexture(textureId); |
| var texture = gl.createTexture(); |
| gl.bindTexture(gl.TEXTURE_2D, texture); |
| 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.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); |
| gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); |
| gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image); |
| return texture; |
| } |
| |
| var currentGL, currentCanvas; |
| |
| function generateGL() { |
| if (currentGL) { |
| return; |
| } |
| |
| currentCanvas = document.createElement("canvas"); |
| currentGL = currentCanvas.getContext("webgl", { |
| premultipliedalpha: false |
| }); |
| } |
| |
| var smaskVertexShaderCode = "\ |
| attribute vec2 a_position; \ |
| attribute vec2 a_texCoord; \ |
| \ |
| uniform vec2 u_resolution; \ |
| \ |
| varying vec2 v_texCoord; \ |
| \ |
| void main() { \ |
| vec2 clipSpace = (a_position / u_resolution) * 2.0 - 1.0; \ |
| gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1); \ |
| \ |
| v_texCoord = a_texCoord; \ |
| } "; |
| var smaskFragmentShaderCode = "\ |
| precision mediump float; \ |
| \ |
| uniform vec4 u_backdrop; \ |
| uniform int u_subtype; \ |
| uniform sampler2D u_image; \ |
| uniform sampler2D u_mask; \ |
| \ |
| varying vec2 v_texCoord; \ |
| \ |
| void main() { \ |
| vec4 imageColor = texture2D(u_image, v_texCoord); \ |
| vec4 maskColor = texture2D(u_mask, v_texCoord); \ |
| if (u_backdrop.a > 0.0) { \ |
| maskColor.rgb = maskColor.rgb * maskColor.a + \ |
| u_backdrop.rgb * (1.0 - maskColor.a); \ |
| } \ |
| float lum; \ |
| if (u_subtype == 0) { \ |
| lum = maskColor.a; \ |
| } else { \ |
| lum = maskColor.r * 0.3 + maskColor.g * 0.59 + \ |
| maskColor.b * 0.11; \ |
| } \ |
| imageColor.a *= lum; \ |
| imageColor.rgb *= imageColor.a; \ |
| gl_FragColor = imageColor; \ |
| } "; |
| var smaskCache = null; |
| |
| function initSmaskGL() { |
| var canvas, gl; |
| generateGL(); |
| canvas = currentCanvas; |
| currentCanvas = null; |
| gl = currentGL; |
| currentGL = null; |
| var vertexShader = createVertexShader(gl, smaskVertexShaderCode); |
| var fragmentShader = createFragmentShader(gl, smaskFragmentShaderCode); |
| var program = createProgram(gl, [vertexShader, fragmentShader]); |
| gl.useProgram(program); |
| var cache = {}; |
| cache.gl = gl; |
| cache.canvas = canvas; |
| cache.resolutionLocation = gl.getUniformLocation(program, "u_resolution"); |
| cache.positionLocation = gl.getAttribLocation(program, "a_position"); |
| cache.backdropLocation = gl.getUniformLocation(program, "u_backdrop"); |
| cache.subtypeLocation = gl.getUniformLocation(program, "u_subtype"); |
| var texCoordLocation = gl.getAttribLocation(program, "a_texCoord"); |
| var texLayerLocation = gl.getUniformLocation(program, "u_image"); |
| var texMaskLocation = gl.getUniformLocation(program, "u_mask"); |
| var texCoordBuffer = gl.createBuffer(); |
| gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer); |
| gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0]), gl.STATIC_DRAW); |
| gl.enableVertexAttribArray(texCoordLocation); |
| gl.vertexAttribPointer(texCoordLocation, 2, gl.FLOAT, false, 0, 0); |
| gl.uniform1i(texLayerLocation, 0); |
| gl.uniform1i(texMaskLocation, 1); |
| smaskCache = cache; |
| } |
| |
| function composeSMask(layer, mask, properties) { |
| var width = layer.width, |
| height = layer.height; |
| |
| if (!smaskCache) { |
| initSmaskGL(); |
| } |
| |
| var cache = smaskCache, |
| canvas = cache.canvas, |
| gl = cache.gl; |
| canvas.width = width; |
| canvas.height = height; |
| gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight); |
| gl.uniform2f(cache.resolutionLocation, width, height); |
| |
| if (properties.backdrop) { |
| gl.uniform4f(cache.resolutionLocation, properties.backdrop[0], properties.backdrop[1], properties.backdrop[2], 1); |
| } else { |
| gl.uniform4f(cache.resolutionLocation, 0, 0, 0, 0); |
| } |
| |
| gl.uniform1i(cache.subtypeLocation, properties.subtype === "Luminosity" ? 1 : 0); |
| var texture = createTexture(gl, layer, gl.TEXTURE0); |
| var maskTexture = createTexture(gl, mask, gl.TEXTURE1); |
| var buffer = gl.createBuffer(); |
| gl.bindBuffer(gl.ARRAY_BUFFER, buffer); |
| gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([0, 0, width, 0, 0, height, 0, height, width, 0, width, height]), gl.STATIC_DRAW); |
| gl.enableVertexAttribArray(cache.positionLocation); |
| gl.vertexAttribPointer(cache.positionLocation, 2, gl.FLOAT, false, 0, 0); |
| gl.clearColor(0, 0, 0, 0); |
| gl.enable(gl.BLEND); |
| gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA); |
| gl.clear(gl.COLOR_BUFFER_BIT); |
| gl.drawArrays(gl.TRIANGLES, 0, 6); |
| gl.flush(); |
| gl.deleteTexture(texture); |
| gl.deleteTexture(maskTexture); |
| gl.deleteBuffer(buffer); |
| return canvas; |
| } |
| |
| var figuresVertexShaderCode = "\ |
| attribute vec2 a_position; \ |
| attribute vec3 a_color; \ |
| \ |
| uniform vec2 u_resolution; \ |
| uniform vec2 u_scale; \ |
| uniform vec2 u_offset; \ |
| \ |
| varying vec4 v_color; \ |
| \ |
| void main() { \ |
| vec2 position = (a_position + u_offset) * u_scale; \ |
| vec2 clipSpace = (position / u_resolution) * 2.0 - 1.0; \ |
| gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1); \ |
| \ |
| v_color = vec4(a_color / 255.0, 1.0); \ |
| } "; |
| var figuresFragmentShaderCode = "\ |
| precision mediump float; \ |
| \ |
| varying vec4 v_color; \ |
| \ |
| void main() { \ |
| gl_FragColor = v_color; \ |
| } "; |
| var figuresCache = null; |
| |
| function initFiguresGL() { |
| var canvas, gl; |
| generateGL(); |
| canvas = currentCanvas; |
| currentCanvas = null; |
| gl = currentGL; |
| currentGL = null; |
| var vertexShader = createVertexShader(gl, figuresVertexShaderCode); |
| var fragmentShader = createFragmentShader(gl, figuresFragmentShaderCode); |
| var program = createProgram(gl, [vertexShader, fragmentShader]); |
| gl.useProgram(program); |
| var cache = {}; |
| cache.gl = gl; |
| cache.canvas = canvas; |
| cache.resolutionLocation = gl.getUniformLocation(program, "u_resolution"); |
| cache.scaleLocation = gl.getUniformLocation(program, "u_scale"); |
| cache.offsetLocation = gl.getUniformLocation(program, "u_offset"); |
| cache.positionLocation = gl.getAttribLocation(program, "a_position"); |
| cache.colorLocation = gl.getAttribLocation(program, "a_color"); |
| figuresCache = cache; |
| } |
| |
| function drawFigures(width, height, backgroundColor, figures, context) { |
| if (!figuresCache) { |
| initFiguresGL(); |
| } |
| |
| var cache = figuresCache, |
| canvas = cache.canvas, |
| gl = cache.gl; |
| canvas.width = width; |
| canvas.height = height; |
| gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight); |
| gl.uniform2f(cache.resolutionLocation, width, height); |
| var count = 0; |
| var i, ii, rows; |
| |
| for (i = 0, ii = figures.length; i < ii; i++) { |
| switch (figures[i].type) { |
| case "lattice": |
| rows = figures[i].coords.length / figures[i].verticesPerRow | 0; |
| count += (rows - 1) * (figures[i].verticesPerRow - 1) * 6; |
| break; |
| |
| case "triangles": |
| count += figures[i].coords.length; |
| break; |
| } |
| } |
| |
| var coords = new Float32Array(count * 2); |
| var colors = new Uint8Array(count * 3); |
| var coordsMap = context.coords, |
| colorsMap = context.colors; |
| var pIndex = 0, |
| cIndex = 0; |
| |
| for (i = 0, ii = figures.length; i < ii; i++) { |
| var figure = figures[i], |
| ps = figure.coords, |
| cs = figure.colors; |
| |
| switch (figure.type) { |
| case "lattice": |
| var cols = figure.verticesPerRow; |
| rows = ps.length / cols | 0; |
| |
| for (var row = 1; row < rows; row++) { |
| var offset = row * cols + 1; |
| |
| for (var col = 1; col < cols; col++, offset++) { |
| coords[pIndex] = coordsMap[ps[offset - cols - 1]]; |
| coords[pIndex + 1] = coordsMap[ps[offset - cols - 1] + 1]; |
| coords[pIndex + 2] = coordsMap[ps[offset - cols]]; |
| coords[pIndex + 3] = coordsMap[ps[offset - cols] + 1]; |
| coords[pIndex + 4] = coordsMap[ps[offset - 1]]; |
| coords[pIndex + 5] = coordsMap[ps[offset - 1] + 1]; |
| colors[cIndex] = colorsMap[cs[offset - cols - 1]]; |
| colors[cIndex + 1] = colorsMap[cs[offset - cols - 1] + 1]; |
| colors[cIndex + 2] = colorsMap[cs[offset - cols - 1] + 2]; |
| colors[cIndex + 3] = colorsMap[cs[offset - cols]]; |
| colors[cIndex + 4] = colorsMap[cs[offset - cols] + 1]; |
| colors[cIndex + 5] = colorsMap[cs[offset - cols] + 2]; |
| colors[cIndex + 6] = colorsMap[cs[offset - 1]]; |
| colors[cIndex + 7] = colorsMap[cs[offset - 1] + 1]; |
| colors[cIndex + 8] = colorsMap[cs[offset - 1] + 2]; |
| coords[pIndex + 6] = coords[pIndex + 2]; |
| coords[pIndex + 7] = coords[pIndex + 3]; |
| coords[pIndex + 8] = coords[pIndex + 4]; |
| coords[pIndex + 9] = coords[pIndex + 5]; |
| coords[pIndex + 10] = coordsMap[ps[offset]]; |
| coords[pIndex + 11] = coordsMap[ps[offset] + 1]; |
| colors[cIndex + 9] = colors[cIndex + 3]; |
| colors[cIndex + 10] = colors[cIndex + 4]; |
| colors[cIndex + 11] = colors[cIndex + 5]; |
| colors[cIndex + 12] = colors[cIndex + 6]; |
| colors[cIndex + 13] = colors[cIndex + 7]; |
| colors[cIndex + 14] = colors[cIndex + 8]; |
| colors[cIndex + 15] = colorsMap[cs[offset]]; |
| colors[cIndex + 16] = colorsMap[cs[offset] + 1]; |
| colors[cIndex + 17] = colorsMap[cs[offset] + 2]; |
| pIndex += 12; |
| cIndex += 18; |
| } |
| } |
| |
| break; |
| |
| case "triangles": |
| for (var j = 0, jj = ps.length; j < jj; j++) { |
| coords[pIndex] = coordsMap[ps[j]]; |
| coords[pIndex + 1] = coordsMap[ps[j] + 1]; |
| colors[cIndex] = colorsMap[cs[j]]; |
| colors[cIndex + 1] = colorsMap[cs[j] + 1]; |
| colors[cIndex + 2] = colorsMap[cs[j] + 2]; |
| pIndex += 2; |
| cIndex += 3; |
| } |
| |
| break; |
| } |
| } |
| |
| if (backgroundColor) { |
| gl.clearColor(backgroundColor[0] / 255, backgroundColor[1] / 255, backgroundColor[2] / 255, 1.0); |
| } else { |
| gl.clearColor(0, 0, 0, 0); |
| } |
| |
| gl.clear(gl.COLOR_BUFFER_BIT); |
| var coordsBuffer = gl.createBuffer(); |
| gl.bindBuffer(gl.ARRAY_BUFFER, coordsBuffer); |
| gl.bufferData(gl.ARRAY_BUFFER, coords, gl.STATIC_DRAW); |
| gl.enableVertexAttribArray(cache.positionLocation); |
| gl.vertexAttribPointer(cache.positionLocation, 2, gl.FLOAT, false, 0, 0); |
| var colorsBuffer = gl.createBuffer(); |
| gl.bindBuffer(gl.ARRAY_BUFFER, colorsBuffer); |
| gl.bufferData(gl.ARRAY_BUFFER, colors, gl.STATIC_DRAW); |
| gl.enableVertexAttribArray(cache.colorLocation); |
| gl.vertexAttribPointer(cache.colorLocation, 3, gl.UNSIGNED_BYTE, false, 0, 0); |
| gl.uniform2f(cache.scaleLocation, context.scaleX, context.scaleY); |
| gl.uniform2f(cache.offsetLocation, context.offsetX, context.offsetY); |
| gl.drawArrays(gl.TRIANGLES, 0, count); |
| gl.flush(); |
| gl.deleteBuffer(coordsBuffer); |
| gl.deleteBuffer(colorsBuffer); |
| return canvas; |
| } |
| |
| return { |
| tryInitGL() { |
| try { |
| generateGL(); |
| return !!currentGL; |
| } catch (ex) {} |
| |
| return false; |
| }, |
| |
| composeSMask, |
| drawFigures, |
| |
| cleanup() { |
| if (smaskCache && smaskCache.canvas) { |
| smaskCache.canvas.width = 0; |
| smaskCache.canvas.height = 0; |
| } |
| |
| if (figuresCache && figuresCache.canvas) { |
| figuresCache.canvas.width = 0; |
| figuresCache.canvas.height = 0; |
| } |
| |
| smaskCache = null; |
| figuresCache = null; |
| } |
| |
| }; |
| }(); |