let gl = null; let glCanvas = null; // Aspect ratio and coordinate system // details let aspectRatio; let currentRotation = [0, 1]; let currentScale = 1.0; // Vertex information let vertexArray; let vertexBuffer; let vertexNumComponents; let vertexCount; // Rendering data shared with the // scalers. let uScalingFactor; let uGlobalColor; let uRotationVector; let aVertexPosition; // Animation timing let previousTime = 0.0; let degreesPerSecond = 45; let scalePerSecond = 0.001; const img = new Image(); window.addEventListener("load", startup, false); function startup() { glCanvas = document.getElementById("glcanvas"); gl = glCanvas.getContext("webgl"); const shaderSet = [ { type: gl.VERTEX_SHADER, id: "vertex-shader" }, { type: gl.FRAGMENT_SHADER, id: "fragment-shader" } ]; shaderProgram = buildShaderProgram(shaderSet); aspectRatio = 1; currentRotation = [0, 1]; currentScale = 1; vertexBuffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer); vertexArray = new Float32Array([ -1,1, -1,-1, 1,-1, 1,1 ]); gl.bufferData(gl.ARRAY_BUFFER, vertexArray, gl.STATIC_DRAW); vertexNumComponents = 2; vertexCount = vertexArray.length / vertexNumComponents; currentAngle = 0.0; img.onload = function() { // load texture gl.activeTexture(gl.TEXTURE0); const tex = gl.createTexture(); gl.bindTexture(gl.TEXTURE_2D, tex); gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, img); // function isPowerOf2(value) { // return (value & (value - 1)) == 0; // } // if (isPowerOf2(img.width) && isPowerOf2(img.height)) { // // Yes, it's a power of 2. Generate mips. // gl.generateMipmap(gl.TEXTURE_2D); // } else { // // No, it's not a power of 2. Turn off mips and set // // wrapping to clamp to edge // } gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); animateScene(); }; img.src = 'images/js-sm.png'; } function buildShaderProgram(shaderInfo) { let program = gl.createProgram(); shaderInfo.forEach(function(desc) { let shader = compileShader(desc.id, desc.type); if (shader) { gl.attachShader(program, shader); } }); gl.linkProgram(program) if (!gl.getProgramParameter(program, gl.LINK_STATUS)) { console.error("Error linking shader program:", gl.getProgramInfoLog(program)); } return program; } function compileShader(id, type) { let code = document.getElementById(id).firstChild.nodeValue; let shader = gl.createShader(type); gl.shaderSource(shader, code); gl.compileShader(shader); if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) { console.error( `Error compiling ${type === gl.VERTEX_SHADER ? "vertex" : "fragment"} shader:`, gl.getShaderInfoLog(shader) ); } return shader; } function animateScene() { gl.viewport(0, 0, glCanvas.width, glCanvas.height); gl.clearColor(0.8, 0.9, 1.0, 1.0); gl.clear(gl.COLOR_BUFFER_BIT); let radians = currentAngle * Math.PI / 180.0; currentRotation[0] = Math.sin(radians); currentRotation[1] = Math.cos(radians); gl.useProgram(shaderProgram); uScalingFactor = gl.getUniformLocation(shaderProgram, "uScalingFactor"); uGlobalColor = gl.getUniformLocation(shaderProgram, "uGlobalColor"); uRotationVector = gl.getUniformLocation(shaderProgram, "uRotationVector"); gl.uniform1f(uScalingFactor, currentScale); gl.uniform2fv(uRotationVector, currentRotation); gl.uniform4fv(uGlobalColor, [0.1, 0.7, 0.2, 1.0]); const texLoc = gl.getUniformLocation(shaderProgram, "tex"); gl.uniform1i(texLoc, 0); gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer); aVertexPosition = gl.getAttribLocation(shaderProgram, "aVertexPosition"); gl.vertexAttribPointer(aVertexPosition, vertexNumComponents, gl.FLOAT, false, 0, 0); gl.enableVertexAttribArray(aVertexPosition); gl.drawArrays(gl.TRIANGLE_FAN, 0, vertexCount); window.requestAnimationFrame(function (currentTime) { let secondsElapsed = ((currentTime - previousTime) / 1000.0) let deltaAngle = secondsElapsed * degreesPerSecond; currentAngle = (currentAngle + deltaAngle) % 360; currentScale = 0.5+0.5*(Math.cos(0.0004*currentTime))**2 previousTime = currentTime; animateScene(); }); } startup()