UNPKG

molstar

Version:

A comprehensive macromolecular library.

321 lines 12.7 kB
/** * Copyright (c) 2018-2021 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author Alexander Rose <alexander.rose@weirdbyte.de> */ import { isDebugMode } from '../../mol-util/debug'; import { getErrorDescription } from './context'; import { getProgram } from './program'; import { getShader } from './shader'; export function isWebGL(gl) { return typeof WebGLRenderingContext !== 'undefined' && gl instanceof WebGLRenderingContext; } export function isWebGL2(gl) { return typeof WebGL2RenderingContext !== 'undefined' && gl instanceof WebGL2RenderingContext; } export function getInstancedArrays(gl) { if (isWebGL2(gl)) { return { drawArraysInstanced: gl.drawArraysInstanced.bind(gl), drawElementsInstanced: gl.drawElementsInstanced.bind(gl), vertexAttribDivisor: gl.vertexAttribDivisor.bind(gl), VERTEX_ATTRIB_ARRAY_DIVISOR: gl.VERTEX_ATTRIB_ARRAY_DIVISOR }; } else { var ext = gl.getExtension('ANGLE_instanced_arrays'); if (ext === null) return null; return { drawArraysInstanced: ext.drawArraysInstancedANGLE.bind(ext), drawElementsInstanced: ext.drawElementsInstancedANGLE.bind(ext), vertexAttribDivisor: ext.vertexAttribDivisorANGLE.bind(ext), VERTEX_ATTRIB_ARRAY_DIVISOR: ext.VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE }; } } export function getStandardDerivatives(gl) { if (isWebGL2(gl)) { return { FRAGMENT_SHADER_DERIVATIVE_HINT: gl.FRAGMENT_SHADER_DERIVATIVE_HINT }; } else { var ext = gl.getExtension('OES_standard_derivatives'); if (ext === null) return null; return { FRAGMENT_SHADER_DERIVATIVE_HINT: ext.FRAGMENT_SHADER_DERIVATIVE_HINT_OES }; } } export function getElementIndexUint(gl) { return isWebGL2(gl) ? {} : gl.getExtension('OES_element_index_uint'); } export function getVertexArrayObject(gl) { if (isWebGL2(gl)) { return { VERTEX_ARRAY_BINDING: gl.VERTEX_ARRAY_BINDING, bindVertexArray: gl.bindVertexArray.bind(gl), createVertexArray: gl.createVertexArray.bind(gl), deleteVertexArray: gl.deleteVertexArray.bind(gl), isVertexArray: gl.isVertexArray.bind(gl) }; } else { var ext = gl.getExtension('OES_vertex_array_object'); if (ext === null) return null; return { VERTEX_ARRAY_BINDING: ext.VERTEX_ARRAY_BINDING_OES, bindVertexArray: ext.bindVertexArrayOES.bind(ext), createVertexArray: ext.createVertexArrayOES.bind(ext), deleteVertexArray: ext.deleteVertexArrayOES.bind(ext), isVertexArray: ext.isVertexArrayOES.bind(ext) }; } } export function getTextureFloat(gl) { return isWebGL2(gl) ? {} : gl.getExtension('OES_texture_float'); } export function getTextureFloatLinear(gl) { return gl.getExtension('OES_texture_float_linear'); } export function getTextureHalfFloat(gl) { if (isWebGL2(gl)) { return { HALF_FLOAT: gl.HALF_FLOAT }; } else { var ext = gl.getExtension('OES_texture_half_float'); if (ext === null) return null; return { HALF_FLOAT: ext.HALF_FLOAT_OES }; } } export function getTextureHalfFloatLinear(gl) { return gl.getExtension('OES_texture_half_float_linear'); } export function getBlendMinMax(gl) { if (isWebGL2(gl)) { return { MIN: gl.MIN, MAX: gl.MAX }; } else { var ext = gl.getExtension('EXT_blend_minmax'); if (ext === null) return null; return { MIN: ext.MIN_EXT, MAX: ext.MAX_EXT }; } } export function getFragDepth(gl) { return isWebGL2(gl) ? {} : gl.getExtension('EXT_frag_depth'); } export function getColorBufferFloat(gl) { if (isWebGL2(gl)) { if (gl.getExtension('EXT_color_buffer_float') === null) return null; gl.getExtension('EXT_float_blend'); return { RGBA32F: gl.RGBA32F }; } else { var ext = gl.getExtension('WEBGL_color_buffer_float'); if (ext === null) { // test as support may not be advertised by browsers gl.getExtension('OES_texture_float'); return testColorBuffer(gl, gl.FLOAT) ? { RGBA32F: 0x8814 } : null; } gl.getExtension('EXT_float_blend'); return { RGBA32F: ext.RGBA32F_EXT }; } } export function getColorBufferHalfFloat(gl) { if (isWebGL2(gl)) { if (gl.getExtension('EXT_color_buffer_half_float') === null) return null; gl.getExtension('EXT_float_blend'); return { RGBA16F: gl.RGBA16F }; } else { var ext = gl.getExtension('EXT_color_buffer_half_float'); if (ext === null) { // test as support may not be advertised by browsers gl.getExtension('OES_texture_half_float'); return testColorBuffer(gl, 0x8D61) ? { RGBA16F: 0x881A } : null; } gl.getExtension('EXT_float_blend'); return { RGBA16F: ext.RGBA16F_EXT }; } } export function getDrawBuffers(gl) { if (isWebGL2(gl)) { return { drawBuffers: gl.drawBuffers.bind(gl), COLOR_ATTACHMENT0: gl.COLOR_ATTACHMENT0, COLOR_ATTACHMENT1: gl.COLOR_ATTACHMENT1, COLOR_ATTACHMENT2: gl.COLOR_ATTACHMENT2, COLOR_ATTACHMENT3: gl.COLOR_ATTACHMENT3, COLOR_ATTACHMENT4: gl.COLOR_ATTACHMENT4, COLOR_ATTACHMENT5: gl.COLOR_ATTACHMENT5, COLOR_ATTACHMENT6: gl.COLOR_ATTACHMENT6, COLOR_ATTACHMENT7: gl.COLOR_ATTACHMENT7, DRAW_BUFFER0: gl.DRAW_BUFFER0, DRAW_BUFFER1: gl.DRAW_BUFFER1, DRAW_BUFFER2: gl.DRAW_BUFFER2, DRAW_BUFFER3: gl.DRAW_BUFFER3, DRAW_BUFFER4: gl.DRAW_BUFFER4, DRAW_BUFFER5: gl.DRAW_BUFFER5, DRAW_BUFFER6: gl.DRAW_BUFFER6, DRAW_BUFFER7: gl.DRAW_BUFFER7, MAX_COLOR_ATTACHMENTS: gl.MAX_COLOR_ATTACHMENTS, MAX_DRAW_BUFFERS: gl.MAX_DRAW_BUFFERS, }; } else { var ext = gl.getExtension('WEBGL_draw_buffers'); if (ext === null) return null; return { drawBuffers: ext.drawBuffersWEBGL.bind(ext), COLOR_ATTACHMENT0: ext.COLOR_ATTACHMENT0_WEBGL, COLOR_ATTACHMENT1: ext.COLOR_ATTACHMENT1_WEBGL, COLOR_ATTACHMENT2: ext.COLOR_ATTACHMENT2_WEBGL, COLOR_ATTACHMENT3: ext.COLOR_ATTACHMENT3_WEBGL, COLOR_ATTACHMENT4: ext.COLOR_ATTACHMENT4_WEBGL, COLOR_ATTACHMENT5: ext.COLOR_ATTACHMENT5_WEBGL, COLOR_ATTACHMENT6: ext.COLOR_ATTACHMENT6_WEBGL, COLOR_ATTACHMENT7: ext.COLOR_ATTACHMENT7_WEBGL, DRAW_BUFFER0: ext.DRAW_BUFFER0_WEBGL, DRAW_BUFFER1: ext.DRAW_BUFFER1_WEBGL, DRAW_BUFFER2: ext.DRAW_BUFFER2_WEBGL, DRAW_BUFFER3: ext.DRAW_BUFFER3_WEBGL, DRAW_BUFFER4: ext.DRAW_BUFFER4_WEBGL, DRAW_BUFFER5: ext.DRAW_BUFFER5_WEBGL, DRAW_BUFFER6: ext.DRAW_BUFFER6_WEBGL, DRAW_BUFFER7: ext.DRAW_BUFFER7_WEBGL, MAX_COLOR_ATTACHMENTS: ext.MAX_COLOR_ATTACHMENTS_WEBGL, MAX_DRAW_BUFFERS: ext.MAX_DRAW_BUFFERS_WEBGL, }; } } export function getShaderTextureLod(gl) { return isWebGL2(gl) ? {} : gl.getExtension('EXT_shader_texture_lod'); } export function getDepthTexture(gl) { if (isWebGL2(gl)) { return { UNSIGNED_INT_24_8: gl.UNSIGNED_INT_24_8 }; } else { var ext = gl.getExtension('WEBGL_depth_texture'); if (ext === null) return null; return { UNSIGNED_INT_24_8: ext.UNSIGNED_INT_24_8_WEBGL }; } } export function getSRGB(gl) { if (isWebGL2(gl)) { return { FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING: gl.FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING, SRGB8_ALPHA8: gl.SRGB8_ALPHA8, SRGB8: gl.SRGB8, SRGB: gl.SRGB }; } else { var ext = gl.getExtension('EXT_sRGB'); if (ext === null) return null; return { FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING: ext.FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT, SRGB8_ALPHA8: ext.SRGB8_ALPHA8_EXT, SRGB8: ext.SRGB_ALPHA_EXT, SRGB: ext.SRGB_EXT }; } } // var TextureTestVertShader = "\nattribute vec4 aPosition;\n\nvoid main() {\n gl_Position = aPosition;\n}"; var TextureTestFragShader = "\nprecision mediump float;\nuniform vec4 uColor;\nuniform sampler2D uTexture;\n\nvoid main() {\n gl_FragColor = texture2D(uTexture, vec2(0.5, 0.5)) * uColor;\n}"; var TextureTestTexCoords = new Float32Array([ -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, 1.0 ]); // adapted from https://stackoverflow.com/questions/28827511/ export function testColorBuffer(gl, type) { // setup shaders var vertShader = getShader(gl, { type: 'vert', source: TextureTestVertShader }); var fragShader = getShader(gl, { type: 'frag', source: TextureTestFragShader }); if (!vertShader || !fragShader) return false; // setup program var program = getProgram(gl); gl.attachShader(program, vertShader); gl.attachShader(program, fragShader); gl.linkProgram(program); gl.useProgram(program); // look up where the vertex data needs to go. var positionLocation = gl.getAttribLocation(program, 'aPosition'); var colorLoc = gl.getUniformLocation(program, 'uColor'); if (!colorLoc) { if (isDebugMode) { console.log("error getting 'uColor' uniform location"); } return false; } // provide texture coordinates for the rectangle. var positionBuffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer); gl.bufferData(gl.ARRAY_BUFFER, TextureTestTexCoords, gl.STATIC_DRAW); gl.enableVertexAttribArray(positionLocation); gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0); var whiteTex = gl.createTexture(); var whiteData = new Uint8Array([255, 255, 255, 255]); gl.bindTexture(gl.TEXTURE_2D, whiteTex); gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, whiteData); var tex = gl.createTexture(); gl.bindTexture(gl.TEXTURE_2D, tex); gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, type, null); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); var fb = gl.createFramebuffer(); gl.bindFramebuffer(gl.FRAMEBUFFER, fb); gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0); var status = gl.checkFramebufferStatus(gl.FRAMEBUFFER); if (status !== gl.FRAMEBUFFER_COMPLETE) { if (isDebugMode) { console.log("error creating framebuffer for '" + type + "'"); } return false; } // Draw the rectangle. gl.bindTexture(gl.TEXTURE_2D, whiteTex); gl.uniform4fv(colorLoc, [0, 10, 20, 1]); gl.drawArrays(gl.TRIANGLES, 0, 6); gl.bindTexture(gl.TEXTURE_2D, tex); gl.bindFramebuffer(gl.FRAMEBUFFER, null); gl.clearColor(1, 0, 0, 1); gl.clear(gl.COLOR_BUFFER_BIT); gl.uniform4fv(colorLoc, [0, 1 / 10, 1 / 20, 1]); gl.drawArrays(gl.TRIANGLES, 0, 6); // Check if rendered correctly var pixel = new Uint8Array(4); gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixel); if (pixel[0] !== 0 || pixel[1] < 248 || pixel[2] < 248 || pixel[3] < 254) { if (isDebugMode) { console.log("not able to actually render to '" + type + "' texture"); } return false; } // Check reading from float texture if (type === gl.FLOAT) { gl.bindFramebuffer(gl.FRAMEBUFFER, fb); var floatPixel = new Float32Array(4); gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.FLOAT, floatPixel); var error = gl.getError(); if (error) { if (isDebugMode) { console.log("error reading float pixels: '" + getErrorDescription(gl, error) + "'"); } return false; } } return true; } //# sourceMappingURL=compat.js.map