UNPKG

gl-layer

Version:

A lightweight WebGL setup layer that simplifies renderer management, uniform handling, and cleanup.

383 lines (359 loc) 16.6 kB
function hexToNormalizedRGB(hex) { // Remove # if present var cleanHex = hex.startsWith("#") ? hex.slice(1) : hex; // Parse the hex values to integers var r = parseInt(cleanHex.substring(0, 2), 16); var g = parseInt(cleanHex.substring(2, 4), 16); var b = parseInt(cleanHex.substring(4, 6), 16); // Normalize to 0-1 range return { r: r / 255, g: g / 255, b: b / 255, }; } /****************************************************************************** Copyright (c) Microsoft Corporation. Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ***************************************************************************** */ /* global Reflect, Promise, SuppressedError, Symbol, Iterator */ var __assign = function() { __assign = Object.assign || function __assign(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; function __awaiter(thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); } function __generator(thisArg, body) { var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype); return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); while (g && (g = 0, op[0] && (_ = 0)), _) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; case 5: _.label++; y = op[1]; op = [0]; continue; case 7: op = _.ops.pop(); _.trys.pop(); continue; default: if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } if (t[2]) _.ops.pop(); _.trys.pop(); continue; } op = body.call(thisArg, _); } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } } function __spreadArray(to, from, pack) { if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { if (ar || !(i in from)) { if (!ar) ar = Array.prototype.slice.call(from, 0, i); ar[i] = from[i]; } } return to.concat(ar || Array.prototype.slice.call(from)); } typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) { var e = new Error(message); return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e; }; // Create shader of specific type var loadShader = function (_a) { var gl = _a.gl, type = _a.type, source = _a.source; var shader = gl.createShader(type); if (!shader) return null; gl.shaderSource(shader, source); gl.compileShader(shader); if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) { console.error("An error occurred compiling the shaders: " + gl.getShaderInfoLog(shader)); gl.deleteShader(shader); return null; } return shader; }; // Initialize shader program function initShaderProgram(_a) { var gl = _a.gl, fragmentShaderSource = _a.fragmentShaderSource, vertexShaderSource = _a.vertexShaderSource; var vertexShader = loadShader({ gl: gl, type: gl.VERTEX_SHADER, source: vertexShaderSource, }); var fragmentShader = loadShader({ gl: gl, type: gl.FRAGMENT_SHADER, source: fragmentShaderSource, }); if (!vertexShader || !fragmentShader) return null; var shaderProgram = gl.createProgram(); if (!shaderProgram) return null; gl.attachShader(shaderProgram, vertexShader); gl.attachShader(shaderProgram, fragmentShader); gl.linkProgram(shaderProgram); if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) { console.error("Unable to initialize the shader program: " + gl.getProgramInfoLog(shaderProgram)); return null; } return shaderProgram; } // Initialize buffers for vertex positions and texture coordinates var initBuffers = function (gl) { var positions = [-1, -1, 1.0, -1, -1, 1.0, 1.0, 1.0]; var positionBuffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer); gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW); return { position: positionBuffer, }; }; var initializeWebGL = function (_a) { var gl = _a.gl, uniforms = _a.uniforms, shader = _a.shader, attributes = _a.attributes, _b = _a.vertexPositionName, vertexPositionName = _b === void 0 ? "aVertexPosition" : _b; // Initialize shader program var shaderProgram = initShaderProgram(__assign({ gl: gl }, shader)); if (!shaderProgram) return; var uniformLocations = {}; if (uniforms) for (var _i = 0, uniforms_1 = uniforms; _i < uniforms_1.length; _i++) { var uniform = uniforms_1[_i]; var uniformLocationData = gl.getUniformLocation(shaderProgram, uniform.webglName); if (uniformLocationData) uniformLocations[uniform.uniformName] = uniformLocationData; } var attribLocations = {}; if (attributes) for (var _c = 0, attributes_1 = attributes; _c < attributes_1.length; _c++) { var attribute = attributes_1[_c]; var attribLocationData = gl.getAttribLocation(shaderProgram, attribute.webglName); if (attribLocationData) attribLocations[attribute.attributeName] = attribLocationData; } var programInfoRefCurrent = { program: shaderProgram, attribLocations: __assign({ vertexPosition: gl.getAttribLocation(shaderProgram, vertexPositionName) }, attribLocations), uniformLocations: __assign({}, uniformLocations), }; // Initialize buffers var buffersRefCurrent = initBuffers(gl); return { programInfoRefCurrent: programInfoRefCurrent, buffersRefCurrent: buffersRefCurrent, }; }; var cleanupWebGLResources = function (_a) { return __awaiter(void 0, [_a], void 0, function (_b) { var gl_1, buffers, program, shaders, texture, framebuffer, renderbuffer; var canvas = _b.canvas; return __generator(this, function (_c) { if (canvas) { gl_1 = canvas.getContext("webgl"); if (gl_1) { buffers = gl_1.getParameter(gl_1.ARRAY_BUFFER_BINDING); if (buffers) gl_1.deleteBuffer(buffers); program = gl_1.getParameter(gl_1.CURRENT_PROGRAM); if (program) { shaders = gl_1.getAttachedShaders(program); if (shaders) { shaders.forEach(function (shader) { if (shader) gl_1.deleteShader(shader); }); } gl_1.deleteProgram(program); } texture = gl_1.getParameter(gl_1.TEXTURE_BINDING_2D); if (texture) gl_1.deleteTexture(texture); framebuffer = gl_1.getParameter(gl_1.FRAMEBUFFER_BINDING); if (framebuffer) gl_1.deleteFramebuffer(framebuffer); renderbuffer = gl_1.getParameter(gl_1.RENDERBUFFER_BINDING); if (renderbuffer) gl_1.deleteRenderbuffer(renderbuffer); } } return [2 /*return*/]; }); }); }; // Load texture from image URL var loadTexture = function (_a) { var gl = _a.gl, url = _a.url; var texture = gl.createTexture(); if (!texture) return Promise.resolve(null); gl.bindTexture(gl.TEXTURE_2D, texture); // Put a single pixel in the texture so we can use it immediately var level = 0; var internalFormat = gl.RGBA; var width = 1.0; var height = 1.0; var border = 0; var srcFormat = gl.RGBA; var srcType = gl.UNSIGNED_BYTE; var pixel = new Uint8Array([0, 0, 0, 255]); gl.texImage2D(gl.TEXTURE_2D, level, internalFormat, width, height, border, srcFormat, srcType, pixel); // Load the image return new Promise(function (resolve) { var image = new Image(); image.onload = function () { gl.bindTexture(gl.TEXTURE_2D, texture); gl.texImage2D(gl.TEXTURE_2D, level, internalFormat, srcFormat, srcType, image); // WebGL1 has different requirements for power of 2 images vs non power of 2 images if (isPowerOf2(image.width) && isPowerOf2(image.height)) { gl.generateMipmap(gl.TEXTURE_2D); } else { 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.LINEAR); } resolve(texture); }; image.src = url; }); }; var isPowerOf2 = function (value) { return (value & (value - 1)) === 0; }; var loadImageTextures = function (_a) { return __awaiter(void 0, [_a], void 0, function (_b) { var imageTextures, _i, images_1, data, value; var gl = _b.gl, images = _b.images; return __generator(this, function (_c) { switch (_c.label) { case 0: imageTextures = []; _i = 0, images_1 = images; _c.label = 1; case 1: if (!(_i < images_1.length)) return [3 /*break*/, 4]; data = images_1[_i]; return [4 /*yield*/, loadTexture({ gl: gl, url: data })]; case 2: value = _c.sent(); if (value) imageTextures = __spreadArray(__spreadArray([], imageTextures, true), [value], false); _c.label = 3; case 3: _i++; return [3 /*break*/, 1]; case 4: return [2 /*return*/, imageTextures]; } }); }); }; var renderWebGL = function (_a) { return __awaiter(void 0, [_a], void 0, function (_b) { var gl = _b.gl, buffersRefCurrent = _b.buffersRefCurrent, programInfoRefCurrent = _b.programInfoRefCurrent, size = _b.size, secondLayer = _b.secondLayer; return __generator(this, function (_c) { gl.clearColor(0.0, 0.0, 0.0, 1.0); gl.clear(gl.COLOR_BUFFER_BIT); gl.useProgram(programInfoRefCurrent.program); gl.bindBuffer(gl.ARRAY_BUFFER, buffersRefCurrent.position); gl.vertexAttribPointer(programInfoRefCurrent.attribLocations.vertexPosition, 2, gl.FLOAT, false, 0, 0); gl.enableVertexAttribArray(programInfoRefCurrent.attribLocations.vertexPosition); gl.uniform2fv(programInfoRefCurrent.uniformLocations.uResolution, [ size.width, size.height, ]); if (secondLayer) secondLayer(); // Draw the scene gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); return [2 /*return*/]; }); }); }; var setImageUniform = function (_a) { return __awaiter(void 0, [_a], void 0, function (_b) { var textureData, data; var gl = _b.gl, textureNumber = _b.textureNumber, texture = _b.texture, index = _b.index, uniformLocation = _b.uniformLocation, _c = _b.render, render = _c === void 0 ? false : _c; return __generator(this, function (_d) { switch (_d.label) { case 0: textureData = texture; if (!(typeof texture === "string")) return [3 /*break*/, 2]; return [4 /*yield*/, loadImageTextures({ gl: gl, images: [texture] })]; case 1: data = _d.sent(); textureData = data[0]; _d.label = 2; case 2: gl.activeTexture(textureNumber); gl.bindTexture(gl.TEXTURE_2D, textureData); gl.uniform1i(uniformLocation, index); if (render) { gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); } return [2 /*return*/]; } }); }); }; var setFloatUniform = function (_a) { return __awaiter(void 0, [_a], void 0, function (_b) { var gl = _b.gl, value = _b.value, uniformLocation = _b.uniformLocation, _c = _b.render, render = _c === void 0 ? false : _c; return __generator(this, function (_d) { gl.uniform1f(uniformLocation, value); if (render) { gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); } return [2 /*return*/]; }); }); }; var setVec2Uniform = function (_a) { return __awaiter(void 0, [_a], void 0, function (_b) { var gl = _b.gl, value = _b.value, uniformLocation = _b.uniformLocation, _c = _b.render, render = _c === void 0 ? false : _c; return __generator(this, function (_d) { gl.uniform2fv(uniformLocation, [value.x, value.y]); if (render) { gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); } return [2 /*return*/]; }); }); }; var setVec3Uniform = function (_a) { return __awaiter(void 0, [_a], void 0, function (_b) { var gl = _b.gl, value = _b.value, uniformLocation = _b.uniformLocation, _c = _b.render, render = _c === void 0 ? false : _c; return __generator(this, function (_d) { gl.uniform3fv(uniformLocation, [value.x, value.y, value.z]); if (render) { gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); } return [2 /*return*/]; }); }); }; var setVec4Uniform = function (_a) { return __awaiter(void 0, [_a], void 0, function (_b) { var gl = _b.gl, value = _b.value, uniformLocation = _b.uniformLocation, _c = _b.render, render = _c === void 0 ? false : _c; return __generator(this, function (_d) { gl.uniform4fv(uniformLocation, [value.x, value.y, value.z, value.a]); if (render) { gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); } return [2 /*return*/]; }); }); }; export { cleanupWebGLResources, hexToNormalizedRGB, initShaderProgram, initializeWebGL, loadImageTextures, loadShader, loadTexture, renderWebGL, setFloatUniform, setImageUniform, setVec2Uniform, setVec3Uniform, setVec4Uniform }; //# sourceMappingURL=index.esm.js.map