UNPKG

@egjs/view360

Version:

360 integrated viewing solution from inside-out view to outside-in view. It provides user-friendly service by rotating 360 degrees through various user interaction such as motion sensor and touch.

195 lines (157 loc) 5.01 kB
import agent from "@egjs/agent"; const WEBGL_ERROR_CODE = { "0": "NO_ERROR", "1280": "INVALID_ENUM", "1281": "INVALID_VALUE", "1282": "INVALID_OPERATION", "1285": "OUT_OF_MEMORY", "1286": "INVALID_FRAMEBUFFER_OPERATION", "37442": "CONTEXT_LOST_WEBGL" }; let webglAvailability = null; let MAX_TEXTURE_SIZE_FOR_TEST = null; export default class WebGLUtils { static createShader(gl, type, source) { const shader = gl.createShader(type); gl.shaderSource(shader, source); gl.compileShader(shader); const success = gl.getShaderParameter(shader, gl.COMPILE_STATUS); if (success) { return shader; } gl.deleteShader(shader); return null; } static createProgram(gl, vertexShader, fragmentShader) { const program = gl.createProgram(); gl.attachShader(program, vertexShader); gl.attachShader(program, fragmentShader); gl.linkProgram(program); const success = gl.getProgramParameter(program, gl.LINK_STATUS); if (success) { return program; } gl.deleteProgram(program); return null; } static initBuffer(gl, target /* bind point */, data, itemSize, attr) { const buffer = gl.createBuffer(); gl.bindBuffer(target, buffer); gl.bufferData(target, data, gl.STATIC_DRAW); if (buffer) { buffer.itemSize = itemSize; buffer.numItems = data.length / itemSize; } if (attr !== undefined) { gl.enableVertexAttribArray(attr); gl.vertexAttribPointer(attr, buffer.itemSize, gl.FLOAT, false, 0, 0); } return buffer; } static getWebglContext(canvas, userContextAttributes) { const webglIdentifiers = ["webgl", "experimental-webgl", "webkit-3d", "moz-webgl"]; let context = null; const contextAttributes = Object.assign({ preserveDrawingBuffer: false, antialias: false }, userContextAttributes); function onWebglcontextcreationerror(e) { return e.statusMessage; } canvas.addEventListener("webglcontextcreationerror", onWebglcontextcreationerror); for (let i = 0; i < webglIdentifiers.length; i++) { try { context = canvas.getContext(webglIdentifiers[i], contextAttributes); } catch (t) {} if (context) { break; } } canvas.removeEventListener("webglcontextcreationerror", onWebglcontextcreationerror); return context; } static createTexture(gl, textureTarget) { const texture = gl.createTexture(); gl.bindTexture(textureTarget, texture); gl.texParameteri(textureTarget, gl.TEXTURE_MAG_FILTER, gl.LINEAR); gl.texParameteri(textureTarget, gl.TEXTURE_MIN_FILTER, gl.LINEAR); gl.texParameteri(textureTarget, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); gl.texParameteri(textureTarget, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); gl.bindTexture(textureTarget, null); return texture; } /** * Returns the webgl availability of the current browser. * @method WebGLUtils#isWebGLAvailable * @retuen {Boolean} isWebGLAvailable */ static isWebGLAvailable() { if (webglAvailability === null) { const canvas = document.createElement("canvas"); const webglContext = WebGLUtils.getWebglContext(canvas); webglAvailability = !!webglContext; // webglContext Resource forced collection if (webglContext) { const loseContextExtension = webglContext.getExtension("WEBGL_lose_context"); loseContextExtension && loseContextExtension.loseContext(); } } return webglAvailability; } /** * Returns whether webgl is stable in the current browser. * @method WebGLUtils#isStableWebGL * @retuen {Boolean} isStableWebGL */ static isStableWebGL() { const agentInfo = agent(); let isStableWebgl = true; if (agentInfo.os.name === "android" && parseFloat(agentInfo.os.version) <= 4.3) { isStableWebgl = false; } else if (agentInfo.os.name === "android" && parseFloat(agentInfo.os.version) === 4.4) { if (agentInfo.browser.name !== "chrome") { isStableWebgl = false; } } return isStableWebgl; } static getErrorNameFromWebGLErrorCode(code) { if (!(code in WEBGL_ERROR_CODE)) { return "UNKNOWN_ERROR"; } return WEBGL_ERROR_CODE[code]; } /** * This function is wrapper for texImage2D to handle exceptions on texImage2D. * Purpose is to prevent service from being stopped by script error. * * @param {*} gl * @param {*} target * @param {*} pixels */ static texImage2D(gl, target, pixels) { try { gl.texImage2D(target, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, pixels); } catch (error) { /* eslint-disable no-console */ console.error("WebGLUtils.texImage2D error:", error); /* eslint-enable no-console */ } } static getMaxTextureSize(gl) { // WARN: MAX_TEXTURE_SIZE_FOR_TEST is used for test return MAX_TEXTURE_SIZE_FOR_TEST || gl.getParameter(gl.MAX_TEXTURE_SIZE); } } /** * This function should not be used in service code. It's provided only for test purpose. * It should be set to null or 0 when test is done. * * @param {Number} size */ function setMaxTextureSizeForTestOnlyPurpose(size) { MAX_TEXTURE_SIZE_FOR_TEST = size; } export { setMaxTextureSizeForTestOnlyPurpose };