sawine@2: var machine; sawine@8: var renderer; sawine@11: var controller; sawine@11: var camera; sawine@12: var cameraSpeed = {'x': 0.1, 'y': 0.1}; sawine@2: sawine@2: function main() sawine@2: { sawine@2: var canvas = document.getElementById("machine"); sawine@2: var context = new Context(canvas); sawine@10: context.expand(); sawine@2: var gl = context.gl; sawine@7: var object = new Cube(1, context); sawine@2: gl.clearColor(0.0, 0.0, 0.0, 1.0); sawine@2: gl.enable(gl.DEPTH_TEST); sawine@11: machine = new Machine(object); sawine@12: camera = new Camera(cameraSpeed); sawine@11: renderer = new Renderer(camera, context); sawine@11: controller = new Controller(camera, machine, renderer); sawine@6: update(); sawine@6: } sawine@6: sawine@6: function update() sawine@6: { sawine@7: requestAnimFrame(update); sawine@11: controller.update(); sawine@10: machine.scene.rotation.x += (random(0, 2) - 2) * 0.001; sawine@10: machine.scene.rotation.y += (random(0, 3) - 1) * 0.001; sawine@10: machine.scene.rotation.z += (random(0, 2) - 1) * 0.001; sawine@8: machine.update(new Date().getTime()); sawine@8: renderer.update(machine.scene); sawine@2: } sawine@2: sawine@9: function random(min, max) sawine@9: { sawine@10: return (min + Math.random() * (max - min)); sawine@9: } sawine@9: sawine@12: function Camera(speed) sawine@4: { sawine@11: this.x = 0.0; sawine@11: this.y = 0.0; sawine@12: this.speed = speed; sawine@11: } sawine@11: Camera.prototype.moveLeft = function() sawine@11: { sawine@12: this.x += this.speed.x; sawine@11: } sawine@11: Camera.prototype.moveRight = function() sawine@11: { sawine@12: this.x -= this.speed.x; sawine@11: } sawine@11: Camera.prototype.moveUp = function() sawine@11: { sawine@12: this.y -= this.speed.y; sawine@11: } sawine@11: Camera.prototype.moveDown = function() sawine@11: { sawine@12: this.y += this.speed.y; sawine@12: } sawine@12: sawine@12: function moveCameraLeft() sawine@12: { sawine@12: camera.moveLeft(); sawine@12: } sawine@12: sawine@12: function moveCameraRight() sawine@12: { sawine@12: camera.moveRight(); sawine@12: } sawine@12: sawine@12: function moveCameraUp() sawine@12: { sawine@12: camera.moveUp(); sawine@12: } sawine@12: sawine@12: function moveCameraDown() sawine@12: { sawine@12: camera.moveDown(); sawine@11: } sawine@11: sawine@11: function ucode(char) sawine@11: { sawine@11: return char.charCodeAt(0); sawine@11: } sawine@11: sawine@11: function Controller(camera, machine, renderer) sawine@11: { sawine@12: this.actionMap = {'A': moveCameraLeft, sawine@12: 'D': moveCameraRight, sawine@12: 'W': moveCameraUp, sawine@12: 'S': moveCameraDown}; sawine@11: this.keyboard = new Keyboard(this.actionMap); sawine@11: this.mouse = new Mouse(); sawine@11: sawine@11: } sawine@11: Controller.prototype.update = function() sawine@11: { sawine@11: this.keyboard.handle(); sawine@11: } sawine@11: sawine@11: function Mouse() sawine@11: { sawine@11: } sawine@11: function Keyboard(actionMap) sawine@11: { sawine@11: this.actionMap = actionMap; sawine@11: this.pressed = {}; sawine@11: document.onkeydown = handleKeyDown; sawine@11: document.onkeyup = handleKeyUp; sawine@11: } sawine@11: Keyboard.prototype.keyDown = function(event) sawine@11: { sawine@11: this.pressed[event.keyCode] = true; sawine@11: } sawine@11: Keyboard.prototype.keyUp = function(event) sawine@11: { sawine@11: this.pressed[event.keyCode] = false; sawine@11: } sawine@11: Keyboard.prototype.handle = function() sawine@11: { sawine@11: for (key in this.pressed) sawine@11: { sawine@11: if (this.pressed[key]) sawine@11: { sawine@11: key = String.fromCharCode(key); sawine@11: if (this.actionMap[key]) this.actionMap[key](); sawine@11: } sawine@11: } sawine@11: } sawine@11: sawine@11: function handleKeyDown(event) sawine@11: { sawine@11: controller.keyboard.keyDown(event); sawine@11: } sawine@11: sawine@11: function handleKeyUp(event) sawine@11: { sawine@11: controller.keyboard.keyUp(event); sawine@11: } sawine@11: sawine@11: function Renderer(camera, context) sawine@11: { sawine@11: this.camera = camera; sawine@4: this.context = context; sawine@4: this.gl = context.gl; sawine@7: this.matrixStack = []; sawine@4: } sawine@8: Renderer.prototype.update = function(scene) sawine@5: { sawine@5: var gl = this.context.gl; sawine@5: var viewport = this.context.viewport; sawine@5: var shader = this.context.shader; sawine@5: var mvMatrix = this.context.mvMatrix; sawine@5: var pMatrix = this.context.pMatrix; sawine@5: sawine@5: gl.viewport(0, 0, viewport.width, viewport.height); sawine@5: gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); sawine@5: mat4.perspective(45, viewport.width / viewport.height, 0.1, 100.0, pMatrix); sawine@5: sawine@5: mat4.identity(mvMatrix); sawine@11: mat4.translate(mvMatrix, [this.camera.x, this.camera.y, -7.0]); sawine@7: sawine@7: this.pushMatrix(mvMatrix); sawine@7: sawine@10: mat4.rotate(mvMatrix, scene.rotation.x, [1, 0, 0]); sawine@10: mat4.rotate(mvMatrix, scene.rotation.y, [0, 1, 0]); sawine@10: mat4.rotate(mvMatrix, scene.rotation.z, [0, 0, 1]); sawine@7: sawine@5: gl.bindBuffer(gl.ARRAY_BUFFER, scene.positionBuffer); sawine@5: gl.vertexAttribPointer(shader.vertexPosition, scene.positionBuffer.itemSize, gl.FLOAT, false, 0, 0); sawine@5: sawine@5: gl.bindBuffer(gl.ARRAY_BUFFER, scene.colourBuffer); sawine@5: gl.vertexAttribPointer(shader.vertexColour, scene.colourBuffer.itemSize, gl.FLOAT, false, 0, 0); sawine@9: sawine@9: gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, scene.indexBuffer); sawine@5: this.context.updateMatrixUniforms(); sawine@9: gl.drawElements(gl.TRIANGLES, scene.indexBuffer.numItems, gl.UNSIGNED_SHORT, 0); sawine@9: //gl.drawArrays(gl.TRIANGLE_STRIP, 0, scene.positionBuffer.numItems); sawine@7: sawine@7: mvMatrix = this.popMatrix(); sawine@5: sawine@5: if (this.next) this.next.draw(scene); sawine@5: } sawine@8: Renderer.prototype.pushMatrix = function(matrix) sawine@7: { sawine@7: var copy = mat4.create(); sawine@7: mat4.set(matrix, copy); sawine@7: this.matrixStack.push(copy); sawine@7: } sawine@8: Renderer.prototype.popMatrix = function() sawine@7: { sawine@7: if (this.matrixStack.length > 0) return this.matrixStack.pop(); sawine@7: } sawine@5: sawine@5: function Machine(scene) sawine@4: { sawine@5: this.scene = scene; sawine@8: this.lastUpdate = 0; sawine@5: } sawine@8: Machine.prototype.update = function(time) sawine@5: { sawine@8: if (this.lastUpdate != 0) sawine@8: { sawine@9: var diff = time - this.lastUpdate; sawine@8: sawine@8: } sawine@8: this.lastUpdate = time; sawine@4: } sawine@4: sawine@2: function Context(canvas) sawine@2: { sawine@3: this.canvas = canvas; sawine@2: try sawine@2: { sawine@2: this.gl = canvas.getContext("experimental-webgl"); sawine@2: this.viewport = {'width': canvas.width, sawine@2: 'height': canvas.height}; sawine@2: } sawine@2: catch(e) sawine@2: { sawine@2: alert(e); sawine@2: } sawine@2: if (!this.gl) alert("Failed: WebGL init."); sawine@2: this.mvMatrix = mat4.create(); sawine@2: this.pMatrix = mat4.create(); sawine@10: this.shader = new Shader(this); sawine@10: window.onresize = this.expand(); sawine@2: } sawine@2: Context.prototype.updateMatrixUniforms = function() sawine@2: { sawine@2: var gl = this.gl; sawine@2: var program = this.shader; sawine@2: var pMatrix = this.pMatrix; sawine@2: var mvMatrix = this.mvMatrix; sawine@2: gl.uniformMatrix4fv(program.pMatrixUniform, false, pMatrix); sawine@2: gl.uniformMatrix4fv(program.mvMatrixUniform, false, mvMatrix); sawine@2: } sawine@10: Context.prototype.expand = function() sawine@10: { sawine@10: var width = window.innerWidth; sawine@10: var height = window.innerHeight; sawine@10: this.canvas.width = width; sawine@10: this.canvas.height = height; sawine@10: this.viewport.width = width; sawine@10: this.viewport.height = height; sawine@10: } sawine@10: sawine@2: function Shader(context) sawine@2: { sawine@2: var gl = context.gl; sawine@9: var fragment = loadShader(gl, "fragment-shader"); sawine@9: var vertex = loadShader(gl, "vertex-shader"); sawine@2: this.program = gl.createProgram(); sawine@2: gl.attachShader(this.program, vertex); sawine@2: gl.attachShader(this.program, fragment); sawine@2: gl.linkProgram(this.program); sawine@2: sawine@2: if (!gl.getProgramParameter(this.program, gl.LINK_STATUS)) sawine@2: { sawine@2: alert("Failed: Shader init."); sawine@2: } sawine@2: sawine@2: gl.useProgram(this.program); sawine@2: this.vertexPosition = gl.getAttribLocation(this.program, "aVertexPosition"); sawine@2: gl.enableVertexAttribArray(this.vertexPosition); sawine@4: sawine@4: this.vertexColour = gl.getAttribLocation(this.program, "aVertexColour"); sawine@4: gl.enableVertexAttribArray(this.vertexColour); sawine@4: sawine@2: this.pMatrixUniform = gl.getUniformLocation(this.program, "uPMatrix"); sawine@2: this.mvMatrixUniform = gl.getUniformLocation(this.program, "uMVMatrix"); sawine@2: sawine@9: function loadShader(gl, id) sawine@2: { sawine@2: var script = document.getElementById(id); sawine@2: if (!script) return null; sawine@2: sawine@2: var str = ""; sawine@2: var child = script.firstChild; sawine@2: while (child) sawine@2: { sawine@2: if (child.nodeType == 3) str += child.textContent; sawine@2: child = child.nextSibling; sawine@2: } sawine@2: sawine@2: var shader; sawine@2: var common = "x-shader/x-"; sawine@2: if (script.type == common + "fragment") shader = gl.createShader(gl.FRAGMENT_SHADER); sawine@2: else if (script.type == common + "vertex") shader = gl.createShader(gl.VERTEX_SHADER); sawine@2: else return null; sawine@2: sawine@2: gl.shaderSource(shader, str); sawine@2: gl.compileShader(shader); sawine@2: sawine@2: if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) sawine@2: { sawine@2: alert(gl.getShaderInfoLog(shader)); sawine@2: return null; sawine@2: } sawine@2: sawine@2: return shader; sawine@2: } sawine@2: } sawine@2: sawine@2: sawine@7: function Cube(size, context) sawine@2: { sawine@2: var gl = context.gl; sawine@2: this.size = size || 1; sawine@10: this.rotation = {'x': 0.0, 'y': 0.0, 'z': 0.0}; sawine@4: sawine@4: this.positionBuffer = gl.createBuffer(); sawine@4: gl.bindBuffer(gl.ARRAY_BUFFER, this.positionBuffer); sawine@9: var vertices = [ sawine@9: // Front face sawine@9: -1.0, -1.0, 1.0, sawine@9: 1.0, -1.0, 1.0, sawine@9: 1.0, 1.0, 1.0, sawine@9: -1.0, 1.0, 1.0, sawine@9: sawine@9: // Back face sawine@9: -1.0, -1.0, -1.0, sawine@9: -1.0, 1.0, -1.0, sawine@9: 1.0, 1.0, -1.0, sawine@9: 1.0, -1.0, -1.0, sawine@9: sawine@9: // Top face sawine@9: -1.0, 1.0, -1.0, sawine@9: -1.0, 1.0, 1.0, sawine@9: 1.0, 1.0, 1.0, sawine@9: 1.0, 1.0, -1.0, sawine@9: sawine@9: // Bottom face sawine@9: -1.0, -1.0, -1.0, sawine@9: 1.0, -1.0, -1.0, sawine@9: 1.0, -1.0, 1.0, sawine@9: -1.0, -1.0, 1.0, sawine@9: sawine@9: // Right face sawine@9: 1.0, -1.0, -1.0, sawine@9: 1.0, 1.0, -1.0, sawine@9: 1.0, 1.0, 1.0, sawine@9: 1.0, -1.0, 1.0, sawine@9: sawine@9: // Left face sawine@9: -1.0, -1.0, -1.0, sawine@9: -1.0, -1.0, 1.0, sawine@9: -1.0, 1.0, 1.0, sawine@9: -1.0, 1.0, -1.0]; sawine@2: gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW); sawine@4: this.positionBuffer.itemSize = 3; sawine@9: this.positionBuffer.numItems = 24; sawine@4: sawine@4: this.colourBuffer = gl.createBuffer(); sawine@4: gl.bindBuffer(gl.ARRAY_BUFFER, this.colourBuffer); sawine@9: var alpha = 1.0; sawine@9: var colours = [[1.0, 0.0, 0.0, alpha], sawine@9: [0.0, 1.0, 0.0, alpha], sawine@9: [0.0, 0.0, 1.0, alpha], sawine@9: [1.0, 0.0, 1.0, alpha], sawine@9: [1.0, 1.0, 0.0, alpha], sawine@9: [0.0, 1.0, 1.0, alpha]]; sawine@9: var unpackedColours = []; sawine@9: for (var i in colours) sawine@4: { sawine@9: var colour = colours[i]; sawine@9: for (var j = 0; j < 4; j++) sawine@9: { sawine@9: unpackedColours = unpackedColours.concat(colour); sawine@9: } sawine@9: //colours = colours.concat([0.5, 0.5, 1.0, 1.0]); sawine@4: } sawine@9: gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(unpackedColours), gl.STATIC_DRAW); sawine@4: this.colourBuffer.itemSize = 4; sawine@9: this.colourBuffer.numItems = 24; sawine@9: sawine@9: this.indexBuffer = gl.createBuffer(); sawine@9: gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer); sawine@9: var indices = [0, 1, 2, 0, 2, 3, sawine@9: 4, 5, 6, 4, 6, 7, sawine@9: 8, 9, 10, 8, 10, 11, sawine@9: 12, 13, 14, 12, 14, 15, sawine@9: 16, 17, 18, 16, 18, 19, sawine@9: 20, 21, 22, 20, 22, 23]; sawine@9: gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW); sawine@9: this.indexBuffer.itemSize = 1; sawine@9: this.indexBuffer.numItems = 36; sawine@2: }