"use strict"; (() => { const initShaderProgram = (gl) => { const vShaderSrc = ` attribute vec3 position; attribute vec2 textureCoord; uniform mat4 modelMatrix; varying highp vec2 vTextureCoord; void main() { gl_Position = modelMatrix * vec4(position, 1); vTextureCoord = textureCoord; } `; const fShaderSrc = ` varying highp vec2 vTextureCoord; uniform sampler2D sampler; void main() { gl_FragColor = texture2D(sampler, vTextureCoord); } `; const compileShader = (src, type) => { let shader = gl.createShader(type); gl.shaderSource(shader, src); gl.compileShader(shader); let success = gl.getShaderParameter(shader, gl.COMPILE_STATUS); if (!success) { throw gl.getShaderInfoLog(shader); } return shader; } let vShader = compileShader(vShaderSrc, gl.VERTEX_SHADER); let fShader = compileShader(fShaderSrc, gl.FRAGMENT_SHADER); let program = gl.createProgram(); gl.attachShader(program, vShader); gl.attachShader(program, fShader); gl.linkProgram(program); let success = gl.getProgramParameter(program, gl.LINK_STATUS); if (!success) { throw gl.getProgramInfoLog(program); } return program; }; const loadTexture = (gl, image, textureUnit = 0) => { const textureUnitName = `TEXTURE${textureUnit}` const texture = gl.createTexture(); const samplerLocation = gl.getUniformLocation(program, "sampler"); image.addEventListener("load", () => { gl.activeTexture(gl[textureUnitName]); gl.bindTexture(gl.TEXTURE_2D, texture); gl.uniform1i(samplerLocation, textureUnit); gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image); 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); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); }); return texture; }; let viewer = document.getElementById("viewer"); let gl = viewer.getContext("webgl2"); let program = initShaderProgram(gl); let modelMatrixLocation = gl.getUniformLocation(program, "modelMatrix"); // Set up mouse-panning state machine. let θy = 0; let θx = 0.25; const PanState = Object.freeze({ idle: (event) => { if (event.type === "mousedown") { return PanState.panning; } return PanState.idle; }, panning: (event) => { switch (event.type) { case "mouseup": return PanState.idle; case "mouseover": if ((event.buttons & 1) == 0) { return PanState.idle; } break; case "mousemove": θy += event.movementX * 0.025; θx += event.movementY * 0.025; break } return PanState.panning; }, }); const runPanState = (mouseEvent) => { panState = panState(mouseEvent); } var panState = PanState.idle; viewer.addEventListener("mousedown", runPanState); viewer.addEventListener("mouseup", runPanState); viewer.addEventListener("mouseover", runPanState); viewer.addEventListener("mousemove", runPanState); gl.useProgram(program); let vertexBuffer = gl.createBuffer(); let vertices = new Float32Array([ 0, 0, 0, 1, 0, 0, 1, 1, 0, ]); gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer); gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW); const positionLocation = gl.getAttribLocation(program, "position"); // Load texture let image = document.getElementById("image"); loadTexture(gl, image); gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true); let textureCoordBuffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, textureCoordBuffer); const textureCoords = new Float32Array([ 0, 1, 1, 0, 1, 1, ]); gl.bufferData(gl.ARRAY_BUFFER, textureCoords, gl.STATIC_DRAW); const textureCoordLocation = gl.getAttribLocation(program, "textureCoord"); const render = () => { gl.useProgram(program); // Create the transformation matrix. let modelMatrix = mat4.create(); mat4.rotateX(modelMatrix, modelMatrix, θx); mat4.rotateY(modelMatrix, modelMatrix, θy); gl.uniformMatrix4fv(modelMatrixLocation, false, modelMatrix); gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer); gl.enableVertexAttribArray(positionLocation); gl.vertexAttribPointer(positionLocation, 3, gl.FLOAT, false, 4 * 3, 0); gl.drawArrays(gl.TRIANGLES, 0, 3); gl.bindBuffer(gl.ARRAY_BUFFER, textureCoordBuffer); gl.enableVertexAttribArray(textureCoordLocation); gl.vertexAttribPointer(textureCoordLocation, 3, gl.FLOAT, false, 4 * 2, 0); requestAnimationFrame(render); }; requestAnimationFrame(render); })();