webgl.js Back

webgl.js is a JavaScript file, which will export some application programming interfaces of WebGL.

module.exports = {
    getContext,
    createShader,
    createProgram,
    activeTexture,
    updateTexture,
    createTexture,
    createUniform,
    setRectangle,
};

/**
 * [getContext: to get the context object of a canvas object]
 * @param  {[type]} canvas     [description]
 * @param  {[type]} options={} [description]
 * @return {[type]}            [description]
 */
function getContext(canvas, options) {
    options = Object.assign({}, options);

    const context = ['webgl', 'experimental-webgl'].reduce((context, key) => {
        if (!context) return context;
        try {
            return canvas.getContext(key, options);
        } catch (ignore) {
            return context;
        }
    }, null);

    !context && document.body.classList.add('no-webgl');
    return context;
}

/**
 * [createShader: cretae the specific shader object from a script]
 * @param  {[type]} gl     [description]
 * @param  {[type]} script [description]
 * @param  {[type]} type   [description]
 * @return {[type]}        [description]
 */
function createShader(gl, script, type) {
    /** create a WebGLShader object */
    const shader = gl.createShader(type);

    /** set the source code in a WebGLShader */
    gl.shaderSource(shader, script);

    /** compile the WebGLShader created before */
    gl.compileShader(shader);

    /** check compiling status */
    const compiled = gl.getShaderParameter(shader, gl.COMPILE_STATUS);

    /** check whether the script can be compiled */
    if (!compiled) {
        /** failed to compile the script of the shader */
        const lastError = gl.getShaderInfoLog(shader);
        console.error(`Error compiling shader '${shader}':${lastError}`);

        /** release the WebGLShader created before */
        gl.deleteShader(shader);

        /** if failed, then return a null */
        return null;
    }

    /** if successful, then return the created shader */
    return shader;
}

function createProgram(gl, vertexScript, fragScript) {
    /** create the vertex shader and the fragment shader respectively */
    const vertexShader = createShader(gl, vertexScript, gl.VERTEX_SHADER);
    const fragShader = createShader(gl, fragScript, gl.FRAGMENT_SHADER);

    /** create a temporary WebGLProgram and link it after attaching both shaders created above */
    const program = gl.createProgram();
    gl.attachShader(program, vertexShader);
    gl.attachShader(program, fragShader);

    gl.linkProgram(program);

    /** check whether the link is available */
    const linked = gl.getProgramParameter(program, gl.LINK_STATUS);

    if (!linked) {
        /** failed to link */
        const lastError = gl.getProgramInfoLog(program);
        console.error(`Error in program linking: ${lastError}`);

        /** release the WebGLProgram created before */
        gl.deleteProgram(program);

        /** if failed, then return a null */
        return null;
    }

    const positionLocation = gl.getAttribLocation(program, 'a_position');
    const texCoordLocation = gl.getAttribLocation(program, 'a_texCoord');

    const texCoordBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer);

    gl.bufferData(gl.ARRAY_BUFFER, 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
    ]), gl.STATIC_DRAW);

    /** enable a vertext attribute array at a given position */
    gl.enableVertexAttribArray(texCoordLocation);

    /** specify the data formats and locations of vertex attributes in a vertex attributes array */
    gl.vertexAttribPointer(texCoordLocation, 2, gl.FLOAT, false, 0, 0);

    /** create a buffer for the position of the rectangle corners */
    const buffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
    gl.enableVertexAttribArray(positionLocation);
    gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);

    return program;
}

function activeTexture(gl, i) {
    /** to select the active texture unit */
    gl.activeTexture(gl['TEXTURE' + i]);
}

function updateTexture(gl, source) {
    /** to specify a 2D texture image with a given source */
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, source);
}

function createTexture(gl, source, i, wrap) {
    if (!wrap) {
        wrap = gl.CLAMP_TO_EDGE;
    }

    const texture = gl.createTexture();
    activeTexture(gl, i);
    gl.bindTexture(gl.TEXTURE_2D, texture);

    /** set the parameters so we can render any size image */
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, wrap);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, wrap);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
    updateTexture(gl, source);

    return texture;
}

function createUniform(gl, program, type, name) {
    /** return the location of a uniform variable. */
    const location = gl.getUniformLocation(program, `u_${name}`);
    gl[`uniform${type}`].apply(undefined, [location, ...[].slice.call(arguments, 1)]);
}

function setRectangle(gl, x, y, width, height) {
    const x1 = x, x2 = x + width, y1 = y, y2 = y + height;
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
        x1, y1,
        x2, y1,
        x1, y2,
        x1, y2,
        x2, y1,
        x2, y2
    ]), gl.STATIC_DRAW);
}
Empty Comments
Sign in GitHub

As the plugin is integrated with a code management system like GitLab or GitHub, you may have to auth with your account before leaving comments around this article.

Notice: This plugin has used Cookie to store your token with an expiration.