| window.addEventListener('load', () => {'use strict'
 
 function main() {
 const canvas = document.getElementById('world')
 const gl = initGL(canvas)
 const shaderProgram = initShader(gl)
 const vertexBuffers = initBuffers(gl)
 
 gl.clearColor(0, 0, 0, 1)
 gl.enable(gl.DEPTH_TEST)
 gl.enable(gl.CULL_FACE)
 gl.cullFace(gl.BACK)
 
 
 let rx = 0, ry = 0, rz = 0
 const modelMatrix = mat4.create()
 const tick = () => {
 requestAnimationFrame(tick)
 
 rx += 0.02
 ry += 0.03
 rz += 0.05
 mat4.identity(modelMatrix)
 mat4.rotateX(modelMatrix, modelMatrix, rx)
 mat4.rotateY(modelMatrix, modelMatrix, ry)
 mat4.rotateZ(modelMatrix, modelMatrix, rz)
 
 drawScene(gl, shaderProgram, vertexBuffers, modelMatrix)
 }
 requestAnimationFrame(tick)
 }
 
 function drawScene(gl, shaderProgram, vertexBuffers, modelMatrix) {
 gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight)
 gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
 
 gl.useProgram(shaderProgram)
 
 
 const pMatrix = mat4.create()
 mat4.perspective(pMatrix, 45, gl.viewportWidth / gl.viewportHeight, 0.1, 100.0)
 gl.uniformMatrix4fv(shaderProgram.uPMatrix, false, pMatrix)
 
 
 const mvMatrix = mat4.create()
 mat4.identity(mvMatrix)
 mat4.translate(mvMatrix, mvMatrix, [0.0, 0.0, -5.0])
 
 
 mat4.multiply(mvMatrix, mvMatrix, modelMatrix)
 gl.uniformMatrix4fv(shaderProgram.uMVMatrix, false, mvMatrix)
 
 gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffers.aVertexPosition)
 gl.vertexAttribPointer(shaderProgram.aVertexPosition,
 vertexBuffers.aVertexPosition.itemSize, gl.FLOAT, false, 0, 0)
 gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffers.aVertexColor)
 gl.vertexAttribPointer(shaderProgram.aVertexColor,
 vertexBuffers.aVertexColor.itemSize, gl.FLOAT, false, 0, 0)
 
 gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, vertexBuffers.indexBuffer)
 gl.drawElements(gl.TRIANGLES, vertexBuffers.indexBuffer.numItems, gl.UNSIGNED_SHORT, 0)
 }
 
 function initShader(gl) {
 const shader_vs_src = `
 attribute vec3 aVertexPosition;
 attribute vec4 aVertexColor;
 
 uniform mat4 uMVMatrix;
 uniform mat4 uPMatrix;
 
 varying vec4 vColor;
 
 void main() {
 gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
 vColor = aVertexColor;
 }`
 const shader_fs_src = `
 precision mediump float;
 
 varying vec4 vColor;
 
 void main() {
 gl_FragColor = vColor;
 }`
 
 const shaderProgram = createShaderProgram(
 gl,
 compileShader(gl, gl.VERTEX_SHADER, shader_vs_src),
 compileShader(gl, gl.FRAGMENT_SHADER, shader_fs_src))
 if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
 alert('Could not initialise shaders')
 }
 
 shaderProgram.aVertexPosition = gl.getAttribLocation(shaderProgram, 'aVertexPosition')
 gl.enableVertexAttribArray(shaderProgram.aVertexPosition)
 
 shaderProgram.aVertexColor = gl.getAttribLocation(shaderProgram, 'aVertexColor')
 gl.enableVertexAttribArray(shaderProgram.aVertexColor)
 
 shaderProgram.uPMatrix = gl.getUniformLocation(shaderProgram, 'uPMatrix')
 shaderProgram.uMVMatrix = gl.getUniformLocation(shaderProgram, 'uMVMatrix')
 
 return shaderProgram
 }
 
 function initBuffers(gl) {
 const positionBuffer = gl.createBuffer()
 gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer)
 const positions = [
 
 -1.0,-1.0, 1.0,   1.0,-1.0, 1.0,  1.0, 1.0, 1.0,  -1.0, 1.0, 1.0,
 
 -1.0,-1.0,-1.0,  -1.0, 1.0,-1.0,  1.0, 1.0,-1.0,   1.0,-1.0,-1.0,
 
 -1.0, 1.0,-1.0,  -1.0, 1.0, 1.0,  1.0, 1.0, 1.0,   1.0, 1.0,-1.0,
 
 -1.0,-1.0,-1.0,   1.0,-1.0,-1.0,  1.0,-1.0, 1.0,  -1.0,-1.0, 1.0,
 
 1.0,-1.0,-1.0,   1.0, 1.0,-1.0,  1.0, 1.0, 1.0,   1.0,-1.0, 1.0,
 
 -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.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW)
 positionBuffer.itemSize = 3
 positionBuffer.numItems = positions.length / positionBuffer.itemSize
 
 const colorBuffer = gl.createBuffer()
 gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer)
 const colors = [
 1,0,0,1, 1,0,0,1, 1,0,0,1, 1,0,0,1,
 0,1,0,1, 0,1,0,1, 0,1,0,1, 0,1,0,1,
 0,0,1,1, 0,0,1,1, 0,0,1,1, 0,0,1,1,
 1,1,0,1, 1,1,0,1, 1,1,0,1, 1,1,0,1,
 0,1,1,1, 0,1,1,1, 0,1,1,1, 0,1,1,1,
 1,0,1,1, 1,0,1,1, 1,0,1,1, 1,0,1,1,
 ]
 gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW)
 colorBuffer.itemSize = 4
 colorBuffer.numItems = colors.length / colorBuffer.itemSize
 
 const indexBuffer = gl.createBuffer()
 gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer)
 const indices = [
 0, 1, 2,      0, 2, 3,
 4, 5, 6,      4, 6, 7,
 8, 9, 10,     8, 10, 11,
 12, 13, 14,   12, 14, 15,
 16, 17, 18,   16, 18, 19,
 20, 21, 22,   20, 22, 23,
 ]
 gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW)
 indexBuffer.itemSize = 1
 indexBuffer.numItems = indices.length / indexBuffer.itemSize
 
 return {
 aVertexPosition: positionBuffer,
 aVertexColor: colorBuffer,
 indexBuffer: indexBuffer,
 }
 }
 
 
 
 const mvMatrixStack = []
 
 function pushMatrix(mtx) {
 const copy = mat4.create()
 mat4.set(mtx, copy)
 mvMatrixStack.push(copy)
 }
 
 function popMatrix() {
 if (mvMatrixStack.length == 0) {
 throw "Invalid popMatrix!"
 }
 return mvMatrixStack.pop()
 }
 
 
 function initGL(canvas) {
 let gl
 try {
 gl = canvas.getContext('experimental-webgl')
 gl.viewportWidth = canvas.width
 gl.viewportHeight = canvas.height
 } catch (e) {
 }
 if (!gl) {
 alert('Could not initialise WebGL, sorry :-(')
 }
 return gl
 }
 
 function createShaderProgram(gl, vertexShader, fragmentShader) {
 const shaderProgram = gl.createProgram()
 gl.attachShader(shaderProgram, vertexShader)
 gl.attachShader(shaderProgram, fragmentShader)
 gl.linkProgram(shaderProgram)
 return shaderProgram
 }
 
 
 function compileShader(gl, type, src) {
 const shader = gl.createShader(type)
 gl.shaderSource(shader, src)
 gl.compileShader(shader)
 if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
 alert(gl.getShaderInfoLog(shader))
 return null
 }
 return shader
 }
 
 
 
 main()
 })
 
 |