scripts/machine.js
author Eugen Sawin <sawine@me73.com>
Mon, 18 Apr 2011 15:30:47 +0200
changeset 18 92eb274bc564
parent 17 8b187fa957ad
child 19 15d61d76daa1
permissions -rwxr-xr-x
Still bugged camera.
     1 var machine;
     2 var renderer;
     3 var controller;
     4 var camera;
     5 var cameraSpeed = {"x": 0.1, "y": 0.1, "z": 0.5, "pitch": 0.5, "yaw": 0.5};
     6 var keyActionMap = {'A': moveCameraLeft,
     7 		 'D': moveCameraRight,
     8 		 'W': moveCameraUp,
     9 		 'S': moveCameraDown};
    10 var mouseActionMap = {"pitch": [[true, false, false], pitchCamera],
    11 		      "yaw": [[true, false, false], yawCamera],
    12                       "wheel": zoomCamera};
    13 
    14 function main()
    15 {
    16     var canvas = document.getElementById("machine");
    17     var context = new Context(canvas);
    18     context.expand();
    19     var gl = context.gl;
    20     var object = new Cube(1, context);
    21     gl.clearColor(0.0, 0.0, 0.0, 1.0);
    22     gl.enable(gl.DEPTH_TEST);
    23     machine = new Machine(object);       
    24     camera = new Camera(cameraSpeed);
    25     renderer = new Renderer(camera, context);
    26     controller = new Controller(keyActionMap, mouseActionMap, camera, machine, renderer);
    27     update();
    28     window.onresize = expandContext;
    29     document.onkeydown = handleKeyDown;
    30     document.onkeyup = handleKeyUp;
    31     canvas.onmousedown = handleMouseDown;
    32     document.onmouseup = handleMouseUp;
    33     document.onmousemove = handleMouseMove;
    34     document.onmousewheel = handleMouseWheel;
    35     //read("config/camera", configureCamera);
    36 }
    37 
    38 function configureCamera(config) {
    39     alert(config);
    40 }
    41 
    42 function update()
    43 {    
    44     requestAnimFrame(update);
    45     controller.update();
    46     machine.scene.rotation.x += (random(0, 2) - 2) * 0.001; 
    47     machine.scene.rotation.y += (random(0, 3) - 1) * 0.001; 
    48     machine.scene.rotation.z += (random(0, 2) - 1) * 0.001;
    49     machine.update(new Date().getTime());
    50     renderer.update(machine.scene);
    51 }
    52 
    53 function random(min, max)
    54 {
    55     return (min + Math.random() * (max - min));
    56 }
    57 
    58 function Camera(speed)
    59 {
    60     this.x = 0.0;
    61     this.y = 0.0;
    62     this.z = 7.0;
    63     this.pitch = 0.0;
    64     this.yaw = 0.0;
    65     this.speed = speed;
    66     this.rotMatrix = mat4.create();
    67     this.transMatrix = mat4.create();
    68     this.matrix = mat4.create();
    69     mat4.identity(this.rotMatrix);
    70     mat4.identity(this.transMatrix);
    71     mat4.identity(this.matrix);
    72 }
    73 Camera.prototype.moveLeft = function()
    74 {
    75     var d = 1 - Math.sin(this.yaw);
    76     this.x -= d * this.speed.x;
    77     this.z += (1 - d) * this.speed.z;
    78 }
    79 Camera.prototype.moveRight = function()
    80 {
    81     var d = 1 - Math.sin(this.yaw);
    82     this.x += d * this.speed.x;
    83     this.z -= (1 - d) * this.speed.z;
    84 }
    85 Camera.prototype.moveUp = function()
    86 {
    87     this.y += this.speed.y;
    88 }
    89 Camera.prototype.moveDown = function()
    90 {
    91     this.y -= this.speed.y;
    92 }
    93 Camera.prototype.zoom = function(delta) 
    94 {
    95     this.x -= Math.sin(this.yaw) * this.speed.x * delta;
    96     this.y -= Math.sin(this.pitch) * this.speed.y * delta;
    97     this.z -= Math.cos(this.yaw) * Math.cos(this.pitch) * this.speed.z * delta;
    98 }
    99 Camera.prototype.changePitch = function(delta)
   100 {
   101     this.pitch += this.speed.pitch * delta;
   102 }
   103 Camera.prototype.changeYaw = function(delta)
   104 {
   105     this.yaw += this.speed.yaw * delta;
   106 }
   107 Camera.prototype.update = function()
   108 {
   109     //mat4.rotate(this.rotMatrix, -this.pitch, [1, 0, 0]);
   110     //mat4.rotate(this.rotMatrix, -this.yaw, [0, 1, 0]);
   111     //mat4.translate(this.transMatrix, [-this.x, -this.y, -this.z]);
   112     mat4.translate(this.matrix, [-this.x, -this.y, -this.z]);
   113     //mat4.rotate(this.matrix, -this.pitch, [1, 0, 0]);
   114     //mat4.rotate(this.matrix, -this.yaw, [0, 1, 0]);
   115     
   116     
   117     this.clear();
   118     //mat4.rotate(mvMatrix, -camera.pitch, [1, 0, 0]);
   119     //mat4.rotate(mvMatrix, -camera.yaw, [0, 1, 0]);
   120     //mat4.translate(mvMatrix, [-camera.x, -camera.y, -camera.z]);
   121 }
   122 Camera.prototype.clear = function()
   123 {
   124     //this.x = this.y = this.z = 0;
   125    //this.pitch = this.yaw = 0;
   126 }
   127 
   128 function Controller(keyActionMap, mouseActionMap, camera, machine, renderer)
   129 { 
   130     this.keyboard = new Keyboard(keyActionMap);
   131     this.mouse = new Mouse(mouseActionMap);
   132    
   133 }
   134 Controller.prototype.update = function()
   135 {
   136     this.keyboard.handle();
   137     this.mouse.handle();
   138 }
   139 
   140 function Mouse(actionMap)
   141 {
   142     this.actionMap = actionMap;
   143     this.pressed = [false, false, false];   
   144     this.wheelDelta = 0;
   145 }
   146 Mouse.prototype.buttonDown = function(event)
   147 {
   148     this.pressed[event.which-1] = true;
   149 }
   150 Mouse.prototype.buttonUp = function(event)
   151 {
   152     this.pressed[event.which-1] = false;
   153 }
   154 Mouse.prototype.move = function(event)
   155 {
   156     this.currentPos = [event.clientX, event.clientY];
   157 }
   158 Mouse.prototype.moveWheel = function(event)
   159 { 
   160     this.wheelDelta += event.wheelDelta;
   161 }
   162 Mouse.prototype.handle = function()
   163 {
   164     var pos = this.currentPos;
   165     if (pos && this.lastPos)
   166     {
   167 	var delta = [pos[0] - this.lastPos[0], pos[1] - this.lastPos[1]];
   168 	delta = normaliseMoveDelta(delta);
   169 	var action = this.actionMap["pitch"];
   170 	if (delta[1] != 0 && action) 
   171 	{
   172 	    for (var i = 0; i < 3; i++)
   173 	    {
   174 		if (this.pressed[i] != action[0][i]) break;
   175 		if (i == 2) action[1](delta[1]);
   176 	    }
   177 	} 
   178 	action = this.actionMap["yaw"];
   179 	if (delta[0] != 0 && action) 
   180 	{
   181 	    for (var i = 0; i < 3; i++)
   182 	    {
   183 		if (this.pressed[i] != action[0][i]) break;
   184 		if (i == 2) action[1](delta[0]);
   185 	    }
   186 	}
   187     }
   188     this.lastPos = pos;
   189     
   190     if (this.wheelDelta != 0)
   191     {
   192 	var delta = normaliseWheelDelta(this.wheelDelta);
   193 	var action = this.actionMap["wheel"];
   194 	if (delta > 0 && action) action(delta);
   195 	else if (delta < 0 && action) action(delta);
   196 	this.wheelDelta = 0;
   197     }
   198     
   199 }
   200 
   201 function normaliseMoveDelta(delta)
   202 {
   203     var width = renderer.context.canvas.width;
   204     var height = renderer.context.canvas.height;
   205     return [delta[0] / width, delta[1] / height];
   206 }
   207 
   208 function normaliseWheelDelta(delta)
   209 {
   210     return delta / 60;
   211 }
   212 
   213 function Keyboard(actionMap)
   214 {
   215     this.actionMap = actionMap;
   216     this.pressed = {};
   217 }
   218 Keyboard.prototype.keyDown = function(event)
   219 {
   220     this.pressed[event.keyCode] = true;    
   221 }
   222 Keyboard.prototype.keyUp = function(event)
   223 {
   224     this.pressed[event.keyCode] = false;
   225 }
   226 Keyboard.prototype.handle = function()
   227 {
   228     for (key in this.pressed)
   229     {
   230 	if (this.pressed[key])
   231 	{
   232 	    key = String.fromCharCode(key);
   233 	    if (this.actionMap[key]) this.actionMap[key](); 
   234 	}
   235     }
   236 }
   237 
   238 function Renderer(camera, context)
   239 {
   240     this.camera = camera;
   241     this.context = context;
   242     this.gl = context.gl;
   243     this.matrixStack = [];
   244 }
   245 Renderer.prototype.update = function(scene)
   246 { 
   247     var gl = this.context.gl;
   248     var viewport = this.context.viewport;
   249     var shader = this.context.shader;
   250     var mvMatrix = this.context.mvMatrix;
   251     var pMatrix = this.context.pMatrix;
   252     var camera = this.camera;
   253     camera.update();
   254 
   255     gl.viewport(0, 0, viewport.width, viewport.height);
   256     gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
   257     mat4.perspective(45, viewport.width / viewport.height, 0.1, 100.0, pMatrix);
   258 
   259     mat4.identity(mvMatrix);
   260     //mat4.multiply(mvMatrix, camera.rotMatrix);
   261     //mat4.multiply(mvMatrix, camera.transMatrix);
   262     mat4.rotate(mvMatrix, -camera.pitch, [1, 0, 0]);
   263     mat4.rotate(mvMatrix, -camera.yaw, [0, 1, 0]);
   264     mat4.translate(mvMatrix, [-camera.x, -camera.y, -camera.z]);
   265     //mat4.multiply(mvMatrix, camera.matrix);
   266     //mat4.rotate(camera.matrix, -camera.pitch, [1, 0, 0]);
   267     //mat4.rotate(camera.matrix, -camera.yaw, [0, 1, 0]);
   268     //camera.yaw = camera.pitch = 0;
   269    
   270     
   271     //this.pushMatrix(mvMatrix);
   272 
   273     //mat4.rotate(mvMatrix, scene.rotation.x, [1, 0, 0]);
   274     //mat4.rotate(mvMatrix, scene.rotation.y, [0, 1, 0]);
   275     //mat4.rotate(mvMatrix, scene.rotation.z, [0, 0, 1]);
   276 
   277     gl.bindBuffer(gl.ARRAY_BUFFER, scene.positionBuffer);
   278     gl.vertexAttribPointer(shader.vertexPosition, scene.positionBuffer.itemSize, gl.FLOAT, false, 0, 0);
   279 
   280     gl.bindBuffer(gl.ARRAY_BUFFER, scene.colourBuffer);
   281     gl.vertexAttribPointer(shader.vertexColour, scene.colourBuffer.itemSize, gl.FLOAT, false, 0, 0);
   282     
   283     gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, scene.indexBuffer);
   284 
   285     this.context.updateMatrixUniforms();
   286     gl.drawElements(gl.TRIANGLES, scene.indexBuffer.numItems, gl.UNSIGNED_SHORT, 0);
   287     //gl.drawArrays(gl.TRIANGLE_STRIP, 0, scene.positionBuffer.numItems);
   288     
   289     //mvMatrix = this.popMatrix();
   290 
   291     if (this.next) this.next.draw(scene);
   292 }
   293 Renderer.prototype.pushMatrix = function(matrix)
   294 {
   295     var copy = mat4.create();
   296     mat4.set(matrix, copy);
   297     this.matrixStack.push(copy);
   298 }
   299 Renderer.prototype.popMatrix = function()    
   300 {
   301     if (this.matrixStack.length > 0) return this.matrixStack.pop();
   302 }
   303 
   304 function Machine(scene)
   305 {
   306     this.scene = scene;
   307     this.lastUpdate = 0;
   308 }
   309 Machine.prototype.update = function(time)
   310 {
   311     if (this.lastUpdate != 0)
   312     {
   313 	var diff = time - this.lastUpdate;
   314 	
   315     }
   316     this.lastUpdate = time;
   317 }
   318 
   319 function Context(canvas)
   320 {
   321     this.canvas = canvas;
   322     try 
   323     {
   324 	this.gl = canvas.getContext("experimental-webgl");
   325 	this.viewport = {'width': canvas.width,
   326 			 'height': canvas.height};
   327     } 
   328     catch(e) 
   329     {
   330 	alert(e);
   331     }
   332     if (!this.gl) alert("Failed: WebGL init.");
   333     this.mvMatrix = mat4.create();
   334     this.pMatrix = mat4.create();
   335     this.shader = new Shader(this);  
   336 }
   337 Context.prototype.updateMatrixUniforms = function()
   338 {
   339     var gl = this.gl;
   340     var program = this.shader;
   341     var pMatrix = this.pMatrix;
   342     var mvMatrix = this.mvMatrix;
   343     gl.uniformMatrix4fv(program.pMatrixUniform, false, pMatrix);
   344     gl.uniformMatrix4fv(program.mvMatrixUniform, false, mvMatrix);
   345 }
   346 Context.prototype.expand = function()
   347 { 
   348     var width = window.innerWidth;
   349     var height = window.innerHeight;
   350     this.canvas.width = width;
   351     this.canvas.height = height;
   352     this.viewport.width = width;
   353     this.viewport.height = height;
   354 }
   355 
   356 function Shader(context)
   357 {
   358     var gl = context.gl;
   359     var fragment = loadShader(gl, "fragment-shader");
   360     var vertex = loadShader(gl, "vertex-shader");
   361     this.program = gl.createProgram();
   362     gl.attachShader(this.program, vertex);
   363     gl.attachShader(this.program, fragment);
   364     gl.linkProgram(this.program);
   365 
   366     if (!gl.getProgramParameter(this.program, gl.LINK_STATUS))
   367     {
   368 	alert("Failed: Shader init.");
   369     }
   370 
   371     gl.useProgram(this.program);
   372     this.vertexPosition = gl.getAttribLocation(this.program, "aVertexPosition");
   373     gl.enableVertexAttribArray(this.vertexPosition);
   374     
   375     this.vertexColour = gl.getAttribLocation(this.program, "aVertexColour");
   376     gl.enableVertexAttribArray(this.vertexColour);
   377 
   378     this.pMatrixUniform = gl.getUniformLocation(this.program, "uPMatrix");
   379     this.mvMatrixUniform = gl.getUniformLocation(this.program, "uMVMatrix");
   380 
   381     function loadShader(gl, id)
   382     {
   383 	var script = document.getElementById(id);
   384 	if (!script) return null;
   385 	
   386 	var str = "";
   387 	var child = script.firstChild;
   388 	while (child)
   389 	{
   390 	    if (child.nodeType == 3) str += child.textContent;
   391 	    child = child.nextSibling;
   392 	}
   393 	
   394 	var shader;
   395 	var common = "x-shader/x-";
   396 	if (script.type == common + "fragment") shader = gl.createShader(gl.FRAGMENT_SHADER);
   397 	else if (script.type == common + "vertex") shader = gl.createShader(gl.VERTEX_SHADER);
   398 	else return null;
   399 
   400 	gl.shaderSource(shader, str);
   401 	gl.compileShader(shader);
   402 
   403 	if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS))
   404         {
   405 	    alert(gl.getShaderInfoLog(shader));
   406 	    return null;
   407 	}
   408 
   409 	return shader;
   410     }
   411 }
   412 
   413 
   414 function Cube(size, context)
   415 {
   416     var gl = context.gl;
   417     this.size = size || 1;
   418     this.rotation = {'x': 0.0, 'y': 0.0, 'z': 0.0};
   419     
   420     this.positionBuffer = gl.createBuffer();
   421     gl.bindBuffer(gl.ARRAY_BUFFER, this.positionBuffer);
   422     var vertices = [
   423 	     // Front face
   424             -1.0, -1.0,  1.0,
   425              1.0, -1.0,  1.0,
   426              1.0,  1.0,  1.0,
   427             -1.0,  1.0,  1.0,
   428  
   429             // Back face
   430             -1.0, -1.0, -1.0,
   431             -1.0,  1.0, -1.0,
   432              1.0,  1.0, -1.0,
   433              1.0, -1.0, -1.0,
   434  
   435             // Top face
   436             -1.0,  1.0, -1.0,
   437             -1.0,  1.0,  1.0,
   438              1.0,  1.0,  1.0,
   439              1.0,  1.0, -1.0,
   440  
   441             // Bottom face
   442             -1.0, -1.0, -1.0,
   443              1.0, -1.0, -1.0,
   444              1.0, -1.0,  1.0,
   445             -1.0, -1.0,  1.0,
   446  
   447             // Right face
   448              1.0, -1.0, -1.0,
   449              1.0,  1.0, -1.0,
   450              1.0,  1.0,  1.0,
   451              1.0, -1.0,  1.0,
   452  
   453             // Left face
   454             -1.0, -1.0, -1.0,
   455             -1.0, -1.0,  1.0,
   456             -1.0,  1.0,  1.0,
   457             -1.0,  1.0, -1.0];
   458     gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
   459     this.positionBuffer.itemSize = 3;
   460     this.positionBuffer.numItems = 24;
   461 
   462     this.colourBuffer = gl.createBuffer();
   463     gl.bindBuffer(gl.ARRAY_BUFFER, this.colourBuffer);
   464     var alpha = 1.0;
   465     var colours = [[1.0, 0.0, 0.0, alpha],
   466 		   [0.0, 1.0, 0.0, alpha],
   467 		   [0.0, 0.0, 1.0, alpha],
   468 		   [1.0, 0.0, 1.0, alpha],
   469 		   [1.0, 1.0, 0.0, alpha],
   470 		   [0.0, 1.0, 1.0, alpha]];
   471     var unpackedColours = [];
   472     for (var i in colours)
   473     {
   474 	var colour = colours[i];
   475 	for (var j = 0; j < 4; j++)
   476 	{
   477 	    unpackedColours = unpackedColours.concat(colour);
   478 	}
   479 	//colours = colours.concat([0.5, 0.5, 1.0, 1.0]);
   480     }
   481     gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(unpackedColours), gl.STATIC_DRAW);
   482     this.colourBuffer.itemSize = 4;
   483     this.colourBuffer.numItems = 24;
   484 
   485     this.indexBuffer = gl.createBuffer();
   486     gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer);
   487     var indices = [0, 1, 2, 0, 2, 3,
   488 		   4, 5, 6, 4, 6, 7,
   489 		   8, 9, 10, 8, 10, 11,
   490 		   12, 13, 14, 12, 14, 15,
   491 		   16, 17, 18, 16, 18, 19,
   492 		   20, 21, 22, 20, 22, 23];
   493     gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);
   494     this.indexBuffer.itemSize = 1;
   495     this.indexBuffer.numItems = 36;
   496 }
   497 
   498 function read(file, handler)
   499 {
   500     var request = new XMLHttpRequest();
   501     request.open("GET", file);
   502     request.onreadystatechange = function() {
   503 	alert(request.readyState);
   504 	if (request.readyState == 4) {
   505 	    handler(request.responseText);
   506 	}
   507     }
   508     request.send();
   509 }		
   510 
   511 // event handler
   512 function expandContext()
   513 {
   514     renderer.context.expand();
   515 }
   516 
   517 function moveCameraLeft()
   518 {
   519     camera.moveLeft();
   520 }
   521 
   522 function moveCameraRight()
   523 {
   524     camera.moveRight();
   525 }
   526 
   527 function moveCameraUp()
   528 {
   529     camera.moveUp();
   530 }
   531 
   532 function moveCameraDown()
   533 {
   534     camera.moveDown();
   535 }
   536 
   537 function zoomCamera(delta)
   538 {
   539     camera.zoom(delta);
   540 }
   541 
   542 function pitchCamera(delta)
   543 {
   544     camera.changePitch(delta);
   545 }
   546 
   547 function yawCamera(delta)
   548 {
   549     camera.changeYaw(delta);
   550 }
   551 
   552 function handleKeyDown(event)
   553 {
   554     controller.keyboard.keyDown(event);
   555 }
   556 
   557 function handleKeyUp(event)
   558 {
   559     controller.keyboard.keyUp(event);
   560 }
   561 
   562 function handleMouseDown(event)
   563 {
   564     controller.mouse.buttonDown(event);
   565 }
   566 
   567 function handleMouseUp(event)
   568 {
   569     controller.mouse.buttonUp(event);
   570 }
   571 
   572 function handleMouseMove(event)
   573 {
   574     controller.mouse.move(event);
   575 }
   576 
   577 function handleMouseWheel(event)
   578 {
   579     controller.mouse.moveWheel(event);
   580 }