scripts/machine.js
author Eugen Sawin <sawine@me73.com>
Fri, 15 Apr 2011 23:22:22 +0200
changeset 12 c942ba4d4bbf
parent 11 9c0318d0f1c3
child 13 388543f4ea07
permissions -rwxr-xr-x
Added global event handlers.
     1 var machine;
     2 var renderer;
     3 var controller;
     4 var camera;
     5 var cameraSpeed = {'x': 0.1, 'y': 0.1};
     6 
     7 function main()
     8 {
     9     var canvas = document.getElementById("machine");
    10     var context = new Context(canvas);
    11     context.expand();
    12     var gl = context.gl;
    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);
    20     update();
    21 }
    22 
    23 function update()
    24 {    
    25     requestAnimFrame(update);
    26     controller.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);
    32 }
    33 
    34 function random(min, max)
    35 {
    36     return (min + Math.random() * (max - min));
    37 }
    38 
    39 function Camera(speed)
    40 {
    41     this.x = 0.0;
    42     this.y = 0.0;
    43     this.speed = speed;
    44 }
    45 Camera.prototype.moveLeft = function()
    46 {
    47     this.x += this.speed.x;
    48 }
    49 Camera.prototype.moveRight = function()
    50 {
    51     this.x -= this.speed.x;
    52 }
    53 Camera.prototype.moveUp = function()
    54 {
    55     this.y -= this.speed.y;
    56 }
    57 Camera.prototype.moveDown = function()
    58 {
    59     this.y += this.speed.y;
    60 }
    61 
    62 function moveCameraLeft()
    63 {
    64     camera.moveLeft();
    65 }
    66 
    67 function moveCameraRight()
    68 {
    69     camera.moveRight();
    70 }
    71 
    72 function moveCameraUp()
    73 {
    74     camera.moveUp();
    75 }
    76 
    77 function moveCameraDown()
    78 {
    79     camera.moveDown();
    80 }
    81 
    82 function ucode(char)
    83 {
    84     return char.charCodeAt(0);
    85 }
    86      
    87 function Controller(camera, machine, renderer)
    88 { 
    89     this.actionMap = {'A': moveCameraLeft,
    90                       'D': moveCameraRight,
    91                       'W': moveCameraUp,
    92                       'S': moveCameraDown};
    93     this.keyboard = new Keyboard(this.actionMap);
    94     this.mouse = new Mouse();
    95    
    96 }
    97 Controller.prototype.update = function()
    98 {
    99     this.keyboard.handle();
   100 }
   101 
   102 function Mouse()
   103 {
   104 }
   105 function Keyboard(actionMap)
   106 {
   107     this.actionMap = actionMap;
   108     this.pressed = {};
   109     document.onkeydown = handleKeyDown;
   110     document.onkeyup = handleKeyUp;
   111 }
   112 Keyboard.prototype.keyDown = function(event)
   113 {
   114     this.pressed[event.keyCode] = true;    
   115 }
   116 Keyboard.prototype.keyUp = function(event)
   117 {
   118     this.pressed[event.keyCode] = false;
   119 }
   120 Keyboard.prototype.handle = function()
   121 {
   122     for (key in this.pressed)
   123     {
   124 	if (this.pressed[key])
   125 	{
   126 	    key = String.fromCharCode(key);
   127 	    if (this.actionMap[key]) this.actionMap[key](); 
   128 	}
   129     }
   130 }
   131 
   132 function handleKeyDown(event)
   133 {
   134     controller.keyboard.keyDown(event);
   135 }
   136 
   137 function handleKeyUp(event)
   138 {
   139     controller.keyboard.keyUp(event);
   140 }
   141 
   142 function Renderer(camera, context)
   143 {
   144     this.camera = camera;
   145     this.context = context;
   146     this.gl = context.gl;
   147     this.matrixStack = [];
   148 }
   149 Renderer.prototype.update = function(scene)
   150 { 
   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;
   156 
   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);
   160 
   161     mat4.identity(mvMatrix);
   162     mat4.translate(mvMatrix, [this.camera.x, this.camera.y, -7.0]);
   163 
   164     this.pushMatrix(mvMatrix);
   165 
   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]);
   169 
   170     gl.bindBuffer(gl.ARRAY_BUFFER, scene.positionBuffer);
   171     gl.vertexAttribPointer(shader.vertexPosition, scene.positionBuffer.itemSize, gl.FLOAT, false, 0, 0);
   172 
   173     gl.bindBuffer(gl.ARRAY_BUFFER, scene.colourBuffer);
   174     gl.vertexAttribPointer(shader.vertexColour, scene.colourBuffer.itemSize, gl.FLOAT, false, 0, 0);
   175     
   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);
   180     
   181     mvMatrix = this.popMatrix();
   182 
   183     if (this.next) this.next.draw(scene);
   184 }
   185 Renderer.prototype.pushMatrix = function(matrix)
   186 {
   187     var copy = mat4.create();
   188     mat4.set(matrix, copy);
   189     this.matrixStack.push(copy);
   190 }
   191 Renderer.prototype.popMatrix = function()    
   192 {
   193     if (this.matrixStack.length > 0) return this.matrixStack.pop();
   194 }
   195 
   196 function Machine(scene)
   197 {
   198     this.scene = scene;
   199     this.lastUpdate = 0;
   200 }
   201 Machine.prototype.update = function(time)
   202 {
   203     if (this.lastUpdate != 0)
   204     {
   205 	var diff = time - this.lastUpdate;
   206 	
   207     }
   208     this.lastUpdate = time;
   209 }
   210 
   211 function Context(canvas)
   212 {
   213     this.canvas = canvas;
   214     try 
   215     {
   216 	this.gl = canvas.getContext("experimental-webgl");
   217 	this.viewport = {'width': canvas.width,
   218 			 'height': canvas.height};
   219     } 
   220     catch(e) 
   221     {
   222 	alert(e);
   223     }
   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();
   229 }
   230 Context.prototype.updateMatrixUniforms = function()
   231 {
   232     var gl = this.gl;
   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);
   238 }
   239 Context.prototype.expand = function()
   240 { 
   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;
   247 }
   248 
   249 function Shader(context)
   250 {
   251     var gl = context.gl;
   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);
   258 
   259     if (!gl.getProgramParameter(this.program, gl.LINK_STATUS))
   260     {
   261 	alert("Failed: Shader init.");
   262     }
   263 
   264     gl.useProgram(this.program);
   265     this.vertexPosition = gl.getAttribLocation(this.program, "aVertexPosition");
   266     gl.enableVertexAttribArray(this.vertexPosition);
   267     
   268     this.vertexColour = gl.getAttribLocation(this.program, "aVertexColour");
   269     gl.enableVertexAttribArray(this.vertexColour);
   270 
   271     this.pMatrixUniform = gl.getUniformLocation(this.program, "uPMatrix");
   272     this.mvMatrixUniform = gl.getUniformLocation(this.program, "uMVMatrix");
   273 
   274     function loadShader(gl, id)
   275     {
   276 	var script = document.getElementById(id);
   277 	if (!script) return null;
   278 	
   279 	var str = "";
   280 	var child = script.firstChild;
   281 	while (child)
   282 	{
   283 	    if (child.nodeType == 3) str += child.textContent;
   284 	    child = child.nextSibling;
   285 	}
   286 	
   287 	var shader;
   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);
   291 	else return null;
   292 
   293 	gl.shaderSource(shader, str);
   294 	gl.compileShader(shader);
   295 
   296 	if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS))
   297         {
   298 	    alert(gl.getShaderInfoLog(shader));
   299 	    return null;
   300 	}
   301 
   302 	return shader;
   303     }
   304 }
   305 
   306 
   307 function Cube(size, context)
   308 {
   309     var gl = context.gl;
   310     this.size = size || 1;
   311     this.rotation = {'x': 0.0, 'y': 0.0, 'z': 0.0};
   312     
   313     this.positionBuffer = gl.createBuffer();
   314     gl.bindBuffer(gl.ARRAY_BUFFER, this.positionBuffer);
   315     var vertices = [
   316 	     // Front face
   317             -1.0, -1.0,  1.0,
   318              1.0, -1.0,  1.0,
   319              1.0,  1.0,  1.0,
   320             -1.0,  1.0,  1.0,
   321  
   322             // Back face
   323             -1.0, -1.0, -1.0,
   324             -1.0,  1.0, -1.0,
   325              1.0,  1.0, -1.0,
   326              1.0, -1.0, -1.0,
   327  
   328             // Top face
   329             -1.0,  1.0, -1.0,
   330             -1.0,  1.0,  1.0,
   331              1.0,  1.0,  1.0,
   332              1.0,  1.0, -1.0,
   333  
   334             // Bottom face
   335             -1.0, -1.0, -1.0,
   336              1.0, -1.0, -1.0,
   337              1.0, -1.0,  1.0,
   338             -1.0, -1.0,  1.0,
   339  
   340             // Right face
   341              1.0, -1.0, -1.0,
   342              1.0,  1.0, -1.0,
   343              1.0,  1.0,  1.0,
   344              1.0, -1.0,  1.0,
   345  
   346             // Left face
   347             -1.0, -1.0, -1.0,
   348             -1.0, -1.0,  1.0,
   349             -1.0,  1.0,  1.0,
   350             -1.0,  1.0, -1.0];
   351     gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
   352     this.positionBuffer.itemSize = 3;
   353     this.positionBuffer.numItems = 24;
   354 
   355     this.colourBuffer = gl.createBuffer();
   356     gl.bindBuffer(gl.ARRAY_BUFFER, this.colourBuffer);
   357     var alpha = 1.0;
   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)
   366     {
   367 	var colour = colours[i];
   368 	for (var j = 0; j < 4; j++)
   369 	{
   370 	    unpackedColours = unpackedColours.concat(colour);
   371 	}
   372 	//colours = colours.concat([0.5, 0.5, 1.0, 1.0]);
   373     }
   374     gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(unpackedColours), gl.STATIC_DRAW);
   375     this.colourBuffer.itemSize = 4;
   376     this.colourBuffer.numItems = 24;
   377 
   378     this.indexBuffer = gl.createBuffer();
   379     gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer);
   380     var indices = [0, 1, 2, 0, 2, 3,
   381 		   4, 5, 6, 4, 6, 7,
   382 		   8, 9, 10, 8, 10, 11,
   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;
   389 }