export function createGLContext(canvas: HTMLCanvasElement, options: any) { const attributes = { 'alpha': true, 'stencil': true, 'preserveDrawingBuffer': true, 'antialias': false }; const names = ['webgl', 'experimental-webgl']; let context = null; /* eslint-disable no-empty */ for (let i = 0; i < names.length; ++i) { try { context = canvas.getContext(names[i], options || attributes); } catch (e) { } if (context) { break; } } return context; /* eslint-enable no-empty */ } /** * Create a shader object * @param gl GL context * @param type the type of the shader object to be created * @param source shader program (string) * @return created shader object, or null if the creation has failed. * @private */ export function compileShader(gl: WebGL2RenderingContext, type: number, source: string) { const shader = gl.createShader(type); gl.shaderSource(shader, source); gl.compileShader(shader); const compiled = gl.getShaderParameter(shader, gl.COMPILE_STATUS); if (!compiled) { const error = gl.getShaderInfoLog(shader); gl.deleteShader(shader); throw new Error('Failed to compile shader: ' + error); } return shader; } /** * Create the linked program object * @param gl WebGL2RenderingContext * @param vert a vertex shader program (string) * @param frag a fragment shader program (string) * @return created program object, or null if the creation has failed * @private */ export function createProgram(gl: WebGL2RenderingContext | any, vert: string, frag: string) { const vertexShader = compileShader(gl, gl.VERTEX_SHADER, vert); const fragmentShader = compileShader(gl, gl.FRAGMENT_SHADER, frag); if (!vertexShader || !fragmentShader) { return null; } const program = gl.createProgram(); if (!program) { return null; } gl.attachShader(program, vertexShader); gl.attachShader(program, fragmentShader); gl.linkProgram(program); return { program, vertexShader, fragmentShader }; } /** * Enable vertex attributes * @param gl WebGL2RenderingContext * @param attributes [[name, stride, type], [name, stride, type]...] * @example * rendererr.enableVertexAttrib([ * ['a_position', 3, 'FLOAT'], * ['a_normal', 3, 'FLOAT'] * ]); * @private */ export function enableVertexAttrib(gl: WebGL2RenderingContext | any, program: WebGLProgram, attributes: any[]) { if (Array.isArray(attributes[0])) { const FSIZE = Float32Array.BYTES_PER_ELEMENT; let STRIDE = 0; for (let i = 0; i < attributes.length; i++) { STRIDE += (attributes[i][1] || 0); } let offset = 0; for (let i = 0; i < attributes.length; i++) { const attr = gl.getAttribLocation(program, attributes[i][0]); if (attr < 0) { throw new Error('Failed to get the storage location of ' + attributes[i][0]); } gl.vertexAttribPointer(attr, attributes[i][1], gl[attributes[i][2] || 'FLOAT'], false, FSIZE * STRIDE, FSIZE * offset); offset += (attributes[i][1] || 0); gl.enableVertexAttribArray(attr); } } else { const attr = gl.getAttribLocation(program, attributes[0]); gl.vertexAttribPointer(attr, attributes[1], gl[attributes[2] || 'FLOAT'], false, 0, 0); gl.enableVertexAttribArray(attr); } } const DEPTH_FUNC_CONSTANTS = { 'never': 0x0200, '<': 0x0201, '=': 0x0202, '<=': 0x0203, '>': 0x0204, '!=': 0x0205, '>=': 0x0206, 'always': 0x0207 }; export function getDepthFunc(v: keyof typeof DEPTH_FUNC_CONSTANTS) { return DEPTH_FUNC_CONSTANTS[v]; }