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