UNPKG

@razorpay/blade

Version:

The Design System that powers Razorpay

201 lines (188 loc) 7.16 kB
import _classCallCheck from '@babel/runtime/helpers/classCallCheck'; import _createClass from '@babel/runtime/helpers/createClass'; /** * WebGL utility functions for shader compilation, program creation, * geometry setup, and texture handling. */ // Fullscreen quad vertices (two triangles covering clip space -1 to 1) // prettier-ignore var FULLSCREEN_QUAD_POSITIONS = new Float32Array([-1, -1, // bottom-left 1, -1, // bottom-right -1, 1, // top-left -1, 1, // top-left 1, -1, // bottom-right 1, 1 // top-right ]); // Standard UV coordinates for fullscreen quad // prettier-ignore var FULLSCREEN_QUAD_UVS = new Float32Array([0, 0, // bottom-left 1, 0, // bottom-right 0, 1, // top-left 0, 1, // top-left 1, 0, // bottom-right 1, 1 // top-right ]); /** * Creates and compiles a WebGL shader */ function createShader(gl, type, 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('Shader compilation error:', gl.getShaderInfoLog(shader)); gl.deleteShader(shader); return null; } return shader; } /** * Creates a WebGL program from vertex and fragment shaders */ function createProgram(gl, vertexSource, fragmentSource) { // Check shader precision and upgrade if needed var format = gl.getShaderPrecisionFormat(gl.FRAGMENT_SHADER, gl.MEDIUM_FLOAT); var precision = format ? format.precision : null; // MEDIUM_FLOAT precision can be 10, 16 or 23 bits depending on device // Shaders fail on 10 bit => we force 23-bit by switching to highp if (precision && precision < 23) { vertexSource = vertexSource.replace(/precision\s+(lowp|mediump)\s+float;/g, 'precision highp float;'); fragmentSource = fragmentSource.replace(/precision\s+(lowp|mediump)\s+float/g, 'precision highp float').replace(/\b(uniform|varying|attribute)\s+(lowp|mediump)\s+(\w+)/g, '$1 highp $3'); } var vertexShader = createShader(gl, gl.VERTEX_SHADER, vertexSource); var fragmentShader = createShader(gl, gl.FRAGMENT_SHADER, fragmentSource); if (!vertexShader || !fragmentShader) return null; var program = gl.createProgram(); if (!program) return null; gl.attachShader(program, vertexShader); gl.attachShader(program, fragmentShader); gl.linkProgram(program); if (!gl.getProgramParameter(program, gl.LINK_STATUS)) { console.error('Program linking error:', gl.getProgramInfoLog(program)); gl.deleteProgram(program); gl.deleteShader(vertexShader); gl.deleteShader(fragmentShader); return null; } // Clean up shaders after successful linking gl.detachShader(program, vertexShader); gl.detachShader(program, fragmentShader); gl.deleteShader(vertexShader); gl.deleteShader(fragmentShader); return program; } /** * Sets up a fullscreen quad with position and UV attributes. * This is the standard geometry for post-processing shaders. * * @param gl - WebGL rendering context * @param program - WebGL program to get attribute locations from * @param positionAttr - Name of position attribute (default: 'position') * @param uvAttr - Name of UV attribute (default: 'uv') * @returns The created buffers for cleanup, or null if setup failed */ function setupFullscreenQuad(gl, program) { var positionAttr = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'position'; var uvAttr = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 'uv'; // Position attribute var positionLocation = gl.getAttribLocation(program, positionAttr); var positionBuffer = gl.createBuffer(); if (!positionBuffer) return null; gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer); gl.bufferData(gl.ARRAY_BUFFER, FULLSCREEN_QUAD_POSITIONS, gl.STATIC_DRAW); gl.enableVertexAttribArray(positionLocation); gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0); // UV attribute var uvLocation = gl.getAttribLocation(program, uvAttr); var uvBuffer = gl.createBuffer(); if (!uvBuffer) return null; gl.bindBuffer(gl.ARRAY_BUFFER, uvBuffer); gl.bufferData(gl.ARRAY_BUFFER, FULLSCREEN_QUAD_UVS, gl.STATIC_DRAW); gl.enableVertexAttribArray(uvLocation); gl.vertexAttribPointer(uvLocation, 2, gl.FLOAT, false, 0, 0); return { positionBuffer: positionBuffer, uvBuffer: uvBuffer }; } /** * OGL-style Texture class for WebGL texture management. * Supports images, videos, and canvas elements as sources. * * @see https://github.com/oframe/ogl/blob/master/src/core/Texture.js */ var Texture = /*#__PURE__*/function () { function Texture(gl) { var _params$textureUnit, _params$minFilter, _params$magFilter, _params$wrapS, _params$wrapT, _params$flipY; var params = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; _classCallCheck(this, Texture); this.gl = gl; this.textureUnit = (_params$textureUnit = params.textureUnit) !== null && _params$textureUnit !== void 0 ? _params$textureUnit : 0; this.minFilter = (_params$minFilter = params.minFilter) !== null && _params$minFilter !== void 0 ? _params$minFilter : gl.NEAREST; this.magFilter = (_params$magFilter = params.magFilter) !== null && _params$magFilter !== void 0 ? _params$magFilter : gl.NEAREST; this.wrapS = (_params$wrapS = params.wrapS) !== null && _params$wrapS !== void 0 ? _params$wrapS : gl.CLAMP_TO_EDGE; this.wrapT = (_params$wrapT = params.wrapT) !== null && _params$wrapT !== void 0 ? _params$wrapT : gl.CLAMP_TO_EDGE; this.flipY = (_params$flipY = params.flipY) !== null && _params$flipY !== void 0 ? _params$flipY : true; this.texture = gl.createTexture(); this.bind(); this.setParameters(); } return _createClass(Texture, [{ key: "bind", value: function bind() { var gl = this.gl; gl.activeTexture(gl.TEXTURE0 + this.textureUnit); gl.bindTexture(gl.TEXTURE_2D, this.texture); } }, { key: "setParameters", value: function setParameters() { var gl = this.gl; gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, this.minFilter); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, this.magFilter); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, this.wrapS); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, this.wrapT); } /** * Upload image data to the texture (OGL-style) */ }, { key: "image", value: function image(source) { var gl = this.gl; if (!source) return; this.bind(); if (this.flipY) { gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true); } gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, source); } /** * Update texture from video frame (call each frame for video textures) */ }, { key: "update", value: function update(source) { this.image(source); } }, { key: "destroy", value: function destroy() { this.gl.deleteTexture(this.texture); this.texture = null; } }]); }(); export { Texture, createProgram, createShader, setupFullscreenQuad }; //# sourceMappingURL=webgl-utils.js.map