WebController - WebGL

This section handles the WebGL creation process.

gfxDraw3D

gfxDraw3D()

The gfxDraw3D function performs the 3D draw process using WebGL. We call it every frame to draw the circles moving with the objects.

  1. We get the WebGL context and perform a clear to delete the old frame content.

  2. We set up the texture properly before doing any draw commands.

            // Performs the 3d draw process
            const gl = this.genvidWebGL.gl;
    
            this.genvidWebGL.clear();
    
            gl.useProgram(this.gfxProg);
    
            // We prepare the program only once (good thing we have a single material).
            gl.enableVertexAttribArray(0);
            gl.enableVertexAttribArray(1);
            gl.enableVertexAttribArray(2);
            gl.activeTexture(gl.TEXTURE0);
            gl.uniform1i(gl.getUniformLocation(this.gfxProg, "tex"), 0);
    
            if (this.gfxProgDataViewproj) {
                gl.uniformMatrix4fv(this.gfxProgLocViewproj, false, this.gfxProgDataViewproj);
            }
    
  3. Finally, we draw the circle.

        // Draws commands.
        if (this.gfxCmdCubes.visible && this.gfxCmdCubes.vtx) {
            gl.bindBuffer(gl.ARRAY_BUFFER, this.gfxCmdCubes.vtx[0]);
            gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 9 * 4, 0 * 4); // Position.
            gl.vertexAttribPointer(1, 2, gl.FLOAT, false, 9 * 4, 3 * 4); // TexCoord.
            gl.vertexAttribPointer(2, 4, gl.FLOAT, false, 9 * 4, 5 * 4); // Color.
            gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.gfxCmdCubes.idx[0]);
            gl.bindTexture(gl.TEXTURE_2D, this.gfxCmdCubes.tex);
            this.genvidWebGL.checkGLError();

            gl.drawElements(gl.TRIANGLES, this.gfxCmdCubes.idx[1], gl.UNSIGNED_SHORT, 0);
            this.genvidWebGL.checkGLError();
        }

gfxInitShaders

gfxInitShaders()

The gfxInitShaders function initializes the shaders during the overall initialization process.

    // Web GL initalization of shaders
    gfxInitShaders() {
        const vShaderStr = [
            "uniform mat4 g_ViewProjMat;",
            "attribute vec3 g_Position;",
            "attribute vec2 g_TexCoord0;",
            "attribute vec4 g_Color0;",
            "varying vec2 texCoord;",
            "varying vec4 color;",
            "void main()",
            "{",
            "   gl_Position = g_ViewProjMat * vec4(g_Position, 1.0);",
            "   texCoord = g_TexCoord0;",
            "   color = g_Color0;",
            "}"
        ].join("\n");
        const fShaderStr = [
            "precision mediump float;",
            "uniform sampler2D tex;",
            "varying vec2 texCoord;",
            "varying vec4 color;",
            "void main()",
            "{",
            "   vec4 texColor = texture2D(tex, texCoord);",
            "   gl_FragColor = texColor * color;", // Texture with color.
            "}"
        ].join("\n");

        const vsh = this.genvidWebGL.loadVertexShader(vShaderStr);
        const fsh = this.genvidWebGL.loadFragmentShader(fShaderStr);
        this.gfxProg = this.genvidWebGL.loadProgram(vsh, fsh, ["g_Position", "g_TexCoord0"]);
        this.gfxProgLocViewproj = this.genvidWebGL.gl.getUniformLocation(this.gfxProg, "g_ViewProjMat");
    }

gfxInitRenderCommands

gfxInitRenderCommands()

The gfxInitRenderCommands function initializes the render commands during the overall initialization process.

    // Web gl initialization of render command
    gfxInitRenderCommands() {
        let gl = this.genvidWebGL.gl;

        // Utility function.
        function handleTextureLoaded(image, texture, options) {
            options = options || {};
            gl.bindTexture(gl.TEXTURE_2D, texture);
            gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR);
            if (options.wrap) {
                gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, options.wrap);
                gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, options.wrap);
            }
            if (options.aniso) {
                let ext = (
                    gl.getExtension("EXT_texture_filter_anisotropic") ||
                    gl.getExtension("MOZ_EXT_texture_filter_anisotropic") ||
                    gl.getExtension("WEBKIT_EXT_texture_filter_anisotropic")
                );
                if (ext) {
                    let max = gl.getParameter(ext.MAX_TEXTURE_MAX_ANISOTROPY_EXT);
                    gl.texParameterf(gl.TEXTURE_2D, ext.TEXTURE_MAX_ANISOTROPY_EXT, max);
                }
            }
            gl.generateMipmap(gl.TEXTURE_2D);
            gl.bindTexture(gl.TEXTURE_2D, null);
        }

        // Cubes.
        {
            // Only prepares textures.
            this.gfxCmdCubes = {
                tex: gl.createTexture(),
                img: new Image(),
                visible: true,
            };
            this.gfxCmdCubes.img.onload = () => {
                handleTextureLoaded(this.gfxCmdCubes.img, this.gfxCmdCubes.tex, {
                    "wrap": gl.CLAMP_TO_EDGE,
                    "aniso": true,
                });
                if (this.gfxDraw3D) this.gfxDraw3D();
            };
            this.gfxCmdCubes.img.src = "img/highlight_full_pa.png";
        }

        this.gfxDraw3D();
    }