Added global event handlers.
5 var cameraSpeed = {'x': 0.1, 'y': 0.1};
9 var canvas = document.getElementById("machine");
10 var context = new Context(canvas);
13 var object = new Cube(1, context);
14 gl.clearColor(0.0, 0.0, 0.0, 1.0);
15 gl.enable(gl.DEPTH_TEST);
16 machine = new Machine(object);
17 camera = new Camera(cameraSpeed);
18 renderer = new Renderer(camera, context);
19 controller = new Controller(camera, machine, renderer);
25 requestAnimFrame(update);
27 machine.scene.rotation.x += (random(0, 2) - 2) * 0.001;
28 machine.scene.rotation.y += (random(0, 3) - 1) * 0.001;
29 machine.scene.rotation.z += (random(0, 2) - 1) * 0.001;
30 machine.update(new Date().getTime());
31 renderer.update(machine.scene);
34 function random(min, max)
36 return (min + Math.random() * (max - min));
39 function Camera(speed)
45 Camera.prototype.moveLeft = function()
47 this.x += this.speed.x;
49 Camera.prototype.moveRight = function()
51 this.x -= this.speed.x;
53 Camera.prototype.moveUp = function()
55 this.y -= this.speed.y;
57 Camera.prototype.moveDown = function()
59 this.y += this.speed.y;
62 function moveCameraLeft()
67 function moveCameraRight()
72 function moveCameraUp()
77 function moveCameraDown()
84 return char.charCodeAt(0);
87 function Controller(camera, machine, renderer)
89 this.actionMap = {'A': moveCameraLeft,
93 this.keyboard = new Keyboard(this.actionMap);
94 this.mouse = new Mouse();
97 Controller.prototype.update = function()
99 this.keyboard.handle();
105 function Keyboard(actionMap)
107 this.actionMap = actionMap;
109 document.onkeydown = handleKeyDown;
110 document.onkeyup = handleKeyUp;
112 Keyboard.prototype.keyDown = function(event)
114 this.pressed[event.keyCode] = true;
116 Keyboard.prototype.keyUp = function(event)
118 this.pressed[event.keyCode] = false;
120 Keyboard.prototype.handle = function()
122 for (key in this.pressed)
124 if (this.pressed[key])
126 key = String.fromCharCode(key);
127 if (this.actionMap[key]) this.actionMap[key]();
132 function handleKeyDown(event)
134 controller.keyboard.keyDown(event);
137 function handleKeyUp(event)
139 controller.keyboard.keyUp(event);
142 function Renderer(camera, context)
144 this.camera = camera;
145 this.context = context;
146 this.gl = context.gl;
147 this.matrixStack = [];
149 Renderer.prototype.update = function(scene)
151 var gl = this.context.gl;
152 var viewport = this.context.viewport;
153 var shader = this.context.shader;
154 var mvMatrix = this.context.mvMatrix;
155 var pMatrix = this.context.pMatrix;
157 gl.viewport(0, 0, viewport.width, viewport.height);
158 gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
159 mat4.perspective(45, viewport.width / viewport.height, 0.1, 100.0, pMatrix);
161 mat4.identity(mvMatrix);
162 mat4.translate(mvMatrix, [this.camera.x, this.camera.y, -7.0]);
164 this.pushMatrix(mvMatrix);
166 mat4.rotate(mvMatrix, scene.rotation.x, [1, 0, 0]);
167 mat4.rotate(mvMatrix, scene.rotation.y, [0, 1, 0]);
168 mat4.rotate(mvMatrix, scene.rotation.z, [0, 0, 1]);
170 gl.bindBuffer(gl.ARRAY_BUFFER, scene.positionBuffer);
171 gl.vertexAttribPointer(shader.vertexPosition, scene.positionBuffer.itemSize, gl.FLOAT, false, 0, 0);
173 gl.bindBuffer(gl.ARRAY_BUFFER, scene.colourBuffer);
174 gl.vertexAttribPointer(shader.vertexColour, scene.colourBuffer.itemSize, gl.FLOAT, false, 0, 0);
176 gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, scene.indexBuffer);
177 this.context.updateMatrixUniforms();
178 gl.drawElements(gl.TRIANGLES, scene.indexBuffer.numItems, gl.UNSIGNED_SHORT, 0);
179 //gl.drawArrays(gl.TRIANGLE_STRIP, 0, scene.positionBuffer.numItems);
181 mvMatrix = this.popMatrix();
183 if (this.next) this.next.draw(scene);
185 Renderer.prototype.pushMatrix = function(matrix)
187 var copy = mat4.create();
188 mat4.set(matrix, copy);
189 this.matrixStack.push(copy);
191 Renderer.prototype.popMatrix = function()
193 if (this.matrixStack.length > 0) return this.matrixStack.pop();
196 function Machine(scene)
201 Machine.prototype.update = function(time)
203 if (this.lastUpdate != 0)
205 var diff = time - this.lastUpdate;
208 this.lastUpdate = time;
211 function Context(canvas)
213 this.canvas = canvas;
216 this.gl = canvas.getContext("experimental-webgl");
217 this.viewport = {'width': canvas.width,
218 'height': canvas.height};
224 if (!this.gl) alert("Failed: WebGL init.");
225 this.mvMatrix = mat4.create();
226 this.pMatrix = mat4.create();
227 this.shader = new Shader(this);
228 window.onresize = this.expand();
230 Context.prototype.updateMatrixUniforms = function()
233 var program = this.shader;
234 var pMatrix = this.pMatrix;
235 var mvMatrix = this.mvMatrix;
236 gl.uniformMatrix4fv(program.pMatrixUniform, false, pMatrix);
237 gl.uniformMatrix4fv(program.mvMatrixUniform, false, mvMatrix);
239 Context.prototype.expand = function()
241 var width = window.innerWidth;
242 var height = window.innerHeight;
243 this.canvas.width = width;
244 this.canvas.height = height;
245 this.viewport.width = width;
246 this.viewport.height = height;
249 function Shader(context)
252 var fragment = loadShader(gl, "fragment-shader");
253 var vertex = loadShader(gl, "vertex-shader");
254 this.program = gl.createProgram();
255 gl.attachShader(this.program, vertex);
256 gl.attachShader(this.program, fragment);
257 gl.linkProgram(this.program);
259 if (!gl.getProgramParameter(this.program, gl.LINK_STATUS))
261 alert("Failed: Shader init.");
264 gl.useProgram(this.program);
265 this.vertexPosition = gl.getAttribLocation(this.program, "aVertexPosition");
266 gl.enableVertexAttribArray(this.vertexPosition);
268 this.vertexColour = gl.getAttribLocation(this.program, "aVertexColour");
269 gl.enableVertexAttribArray(this.vertexColour);
271 this.pMatrixUniform = gl.getUniformLocation(this.program, "uPMatrix");
272 this.mvMatrixUniform = gl.getUniformLocation(this.program, "uMVMatrix");
274 function loadShader(gl, id)
276 var script = document.getElementById(id);
277 if (!script) return null;
280 var child = script.firstChild;
283 if (child.nodeType == 3) str += child.textContent;
284 child = child.nextSibling;
288 var common = "x-shader/x-";
289 if (script.type == common + "fragment") shader = gl.createShader(gl.FRAGMENT_SHADER);
290 else if (script.type == common + "vertex") shader = gl.createShader(gl.VERTEX_SHADER);
293 gl.shaderSource(shader, str);
294 gl.compileShader(shader);
296 if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS))
298 alert(gl.getShaderInfoLog(shader));
307 function Cube(size, context)
310 this.size = size || 1;
311 this.rotation = {'x': 0.0, 'y': 0.0, 'z': 0.0};
313 this.positionBuffer = gl.createBuffer();
314 gl.bindBuffer(gl.ARRAY_BUFFER, this.positionBuffer);
351 gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
352 this.positionBuffer.itemSize = 3;
353 this.positionBuffer.numItems = 24;
355 this.colourBuffer = gl.createBuffer();
356 gl.bindBuffer(gl.ARRAY_BUFFER, this.colourBuffer);
358 var colours = [[1.0, 0.0, 0.0, alpha],
359 [0.0, 1.0, 0.0, alpha],
360 [0.0, 0.0, 1.0, alpha],
361 [1.0, 0.0, 1.0, alpha],
362 [1.0, 1.0, 0.0, alpha],
363 [0.0, 1.0, 1.0, alpha]];
364 var unpackedColours = [];
365 for (var i in colours)
367 var colour = colours[i];
368 for (var j = 0; j < 4; j++)
370 unpackedColours = unpackedColours.concat(colour);
372 //colours = colours.concat([0.5, 0.5, 1.0, 1.0]);
374 gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(unpackedColours), gl.STATIC_DRAW);
375 this.colourBuffer.itemSize = 4;
376 this.colourBuffer.numItems = 24;
378 this.indexBuffer = gl.createBuffer();
379 gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer);
380 var indices = [0, 1, 2, 0, 2, 3,
383 12, 13, 14, 12, 14, 15,
384 16, 17, 18, 16, 18, 19,
385 20, 21, 22, 20, 22, 23];
386 gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);
387 this.indexBuffer.itemSize = 1;
388 this.indexBuffer.numItems = 36;