<html>

<head>
    <script src="https://cdn.jsdelivr.net/npm/gl-matrix@3.4.3/gl-matrix-min.js"></script>
</head>

<body>
    <canvas id="renderCanvas" width="300" height="300"></canvas>

    <script>
        // Get the WebGL context
        const gl = document.getElementById("renderCanvas").getContext("webgl");

        // Create a vertex shader
        const vertexShaderSource =
            `
            attribute vec2 aPosition;
            attribute vec2 aTexCoord;
            uniform mat4 uMvpMatrix;
            varying vec2 vTexCoord;
            
            void main()
            {
                gl_Position = uMvpMatrix * vec4(aPosition, 0.0, 1.0);
                vTexCoord = aTexCoord;
            }`;
        const vShader = gl.createShader(gl.VERTEX_SHADER);
        gl.shaderSource(vShader, vertexShaderSource);
        gl.compileShader(vShader);

        // Create a fragment shader
        const fragmentShaderSource =
            `
            precision mediump float;
            varying vec2 vTexCoord;
            uniform sampler2D uSampler;
            void main()
            {
                gl_FragColor = texture2D(uSampler, vTexCoord);
            }`;
        const fShader = gl.createShader(gl.FRAGMENT_SHADER);
        gl.shaderSource(fShader, fragmentShaderSource);
        gl.compileShader(fShader);

        // Create a shader program
        const program = gl.createProgram();
        gl.attachShader(program, vShader);
        gl.attachShader(program, fShader);
        gl.linkProgram(program);
        gl.useProgram(program);

        // Create a vertex buffer
        const vertexPositions = [
            -0.5, -0.5,
            -0.5, 0.5,
            0.5, -0.5,
            0.5, 0.5
        ];
        const vertexPosBuffer = gl.createBuffer();
        gl.bindBuffer(gl.ARRAY_BUFFER, vertexPosBuffer);
        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertexPositions), gl.STATIC_DRAW);
        // Setting the position attribute
        const aPositionLocation = gl.getAttribLocation(program, "aPosition");
        gl.vertexAttribPointer(aPositionLocation, 2, gl.FLOAT, false, 0, 0);
        gl.enableVertexAttribArray(aPositionLocation);

        // Create a texture coord buffer
        const texCoords = [
            0, 0,
            0, 1,
            2, 0,
            2, 1
        ];
        const texCoordBuffer = gl.createBuffer();
        gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer);
        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(texCoords), gl.STATIC_DRAW);
        // Setting the texture coordinates attribute
        const aTexCoordLocation = gl.getAttribLocation(program, "aTexCoord");
        gl.vertexAttribPointer(aTexCoordLocation, 2, gl.FLOAT, false, 0, 0);
        gl.enableVertexAttribArray(aTexCoordLocation);

        // Set up the camera and projection
        const viewMatrix = glMatrix.mat4.create();
        glMatrix.mat4.lookAt(viewMatrix, [0, 0, 90], [0, 0, 0], [0, 1, 0]);
        const projMatrix = glMatrix.mat4.create();
        glMatrix.mat4.ortho(projMatrix, 0, 100, 100, 0, -100, 100);
        const projViewMatrix = glMatrix.mat4.create();
        glMatrix.mat4.mul(projViewMatrix, projMatrix, viewMatrix);

        // Set object size and object position
        const modelMatrix = glMatrix.mat4.create();
        glMatrix.mat4.translate(modelMatrix, modelMatrix, [50, 50, 1]);
        glMatrix.mat4.scale(modelMatrix, modelMatrix, [60, 30, 1]);

        // Send mvp matrix to shader
        const uMvpMatrixLocation = gl.getUniformLocation(program, "uMvpMatrix");
        const mvpMatrix = glMatrix.mat4.create();
        glMatrix.mat4.mul(mvpMatrix, projViewMatrix, modelMatrix);
        gl.uniformMatrix4fv(uMvpMatrixLocation, false, mvpMatrix);

        const image = new Image();
        image.onload = () =>
        {
            const texture = gl.createTexture();
            gl.bindTexture(gl.TEXTURE_2D, texture);
            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT);
            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT);
            gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, image);
            draw();
        };
        image.crossOrigin = "";
        image.src = "./images/smile.png";

        // Set a color for background
        gl.clearColor(0.2, 0.2, 0.2, 1.0);

        function draw()
        {
            // Clear the background with the selected color
            gl.clear(gl.COLOR_BUFFER_BIT);
            
            // Draw an object
            gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
        }
    </script>

</body>

</html>