scripts/utils3d.js
author Eugen Sawin <sawine@me73.com>
Thu, 31 Mar 2011 23:53:48 +0200
changeset 0 6dc831fb5a60
child 1 92e65293655d
permissions -rwxr-xr-x
Initial.
sawine@0
     1
//
sawine@0
     2
// initWebGL
sawine@0
     3
//
sawine@0
     4
// Initialize the Canvas element with the passed name as a WebGL object and return the
sawine@0
     5
// WebGLRenderingContext. 
sawine@0
     6
//
sawine@0
     7
// Load shaders with the passed names and create a program with them. Return this program 
sawine@0
     8
// in the 'program' property of the returned context.
sawine@0
     9
//
sawine@0
    10
// For each string in the passed attribs array, bind an attrib with that name at that index.
sawine@0
    11
// Once the attribs are bound, link the program and then use it.
sawine@0
    12
//
sawine@0
    13
// Set the clear color to the passed array (4 values) and set the clear depth to the passed value.
sawine@0
    14
// Enable depth testing and blending with a blend func of (SRC_ALPHA, ONE_MINUS_SRC_ALPHA)
sawine@0
    15
//
sawine@0
    16
function initWebGL(canvasName, vshader, fshader, attribs, clearColor, clearDepth)
sawine@0
    17
{
sawine@0
    18
    var canvas = document.getElementById(canvasName);
sawine@0
    19
    var gl = canvas.getContext("webkit-3d");
sawine@0
    20
sawine@0
    21
    // create our shaders
sawine@0
    22
    var vertexShader = loadShader(gl, vshader);
sawine@0
    23
    var fragmentShader = loadShader(gl, fshader);
sawine@0
    24
sawine@0
    25
    if (!vertexShader || !fragmentShader)
sawine@0
    26
        return null;
sawine@0
    27
sawine@0
    28
    // Create the program object
sawine@0
    29
    gl.program = gl.createProgram();
sawine@0
    30
sawine@0
    31
    if (!gl.program)
sawine@0
    32
        return null;
sawine@0
    33
sawine@0
    34
    // Attach our two shaders to the program
sawine@0
    35
    gl.attachShader (gl.program, vertexShader);
sawine@0
    36
    gl.attachShader (gl.program, fragmentShader);
sawine@0
    37
sawine@0
    38
    // Bind attributes
sawine@0
    39
    for (var i in attribs)
sawine@0
    40
        gl.bindAttribLocation (gl.program, i, attribs[i]);
sawine@0
    41
sawine@0
    42
    // Link the program
sawine@0
    43
    gl.linkProgram(gl.program);
sawine@0
    44
sawine@0
    45
    // Check the link status
sawine@0
    46
    var linked = gl.getProgrami(gl.program, gl.LINK_STATUS);
sawine@0
    47
    if (!linked) {
sawine@0
    48
        // something went wrong with the link
sawine@0
    49
        var error = gl.getProgramInfoLog (gl.program);
sawine@0
    50
        console.log("Error in program linking:"+error);
sawine@0
    51
sawine@0
    52
        gl.deleteProgram(gl.program);
sawine@0
    53
        gl.deleteProgram(fragmentShader);
sawine@0
    54
        gl.deleteProgram(vertexShader);
sawine@0
    55
sawine@0
    56
        return null;
sawine@0
    57
    }
sawine@0
    58
sawine@0
    59
    gl.useProgram(gl.program);
sawine@0
    60
sawine@0
    61
    gl.clearColor (clearColor[0], clearColor[1], clearColor[2], clearColor[3]);
sawine@0
    62
    gl.clearDepth (clearDepth);
sawine@0
    63
sawine@0
    64
    gl.enable(gl.DEPTH_TEST);
sawine@0
    65
    gl.enable(gl.BLEND);
sawine@0
    66
    gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
sawine@0
    67
sawine@0
    68
    return gl;
sawine@0
    69
}
sawine@0
    70
sawine@0
    71
//
sawine@0
    72
// loadShader
sawine@0
    73
//
sawine@0
    74
// 'shaderId' is the id of a <script> element containing the shader source string.
sawine@0
    75
// Load this shader and return the WebGLShader object corresponding to it.
sawine@0
    76
//
sawine@0
    77
function loadShader(ctx, shaderId)
sawine@0
    78
{
sawine@0
    79
    var shaderScript = document.getElementById(shaderId);
sawine@0
    80
    if (!shaderScript) {
sawine@0
    81
        console.log("*** Error: shader script '"+shaderId+"' not found");
sawine@0
    82
        return null;
sawine@0
    83
    }
sawine@0
    84
        
sawine@0
    85
    if (shaderScript.type == "x-shader/x-vertex")
sawine@0
    86
        var shaderType = ctx.VERTEX_SHADER;
sawine@0
    87
    else if (shaderScript.type == "x-shader/x-fragment")
sawine@0
    88
        var shaderType = ctx.FRAGMENT_SHADER;
sawine@0
    89
    else {
sawine@0
    90
        console.log("*** Error: shader script '"+shaderId+"' of undefined type '"+shaderScript.type+"'");       
sawine@0
    91
        return null;
sawine@0
    92
    }
sawine@0
    93
sawine@0
    94
    // Create the shader object
sawine@0
    95
    var shader = ctx.createShader(shaderType);
sawine@0
    96
    if (shader == null) {
sawine@0
    97
        console.log("*** Error: unable to create shader '"+shaderId+"'");       
sawine@0
    98
        return null;
sawine@0
    99
    }
sawine@0
   100
sawine@0
   101
    // Load the shader source
sawine@0
   102
    ctx.shaderSource(shader, shaderScript.text);
sawine@0
   103
sawine@0
   104
    // Compile the shader
sawine@0
   105
    ctx.compileShader(shader);
sawine@0
   106
sawine@0
   107
    // Check the compile status
sawine@0
   108
    var compiled = ctx.getShaderi(shader, ctx.COMPILE_STATUS);
sawine@0
   109
    if (!compiled) {
sawine@0
   110
        // Something went wrong during compilation; get the error
sawine@0
   111
        var error = ctx.getShaderInfoLog(shader);
sawine@0
   112
        console.log("*** Error compiling shader '"+shaderId+"':"+error);
sawine@0
   113
        ctx.deleteShader(shader);
sawine@0
   114
        return null;
sawine@0
   115
    }
sawine@0
   116
sawine@0
   117
    return shader;
sawine@0
   118
}
sawine@0
   119
sawine@0
   120
// 
sawine@0
   121
// makeBox
sawine@0
   122
//
sawine@0
   123
// Create a box with vertices, normals and texCoords. Create VBOs for each as well as the index array.
sawine@0
   124
// Return an object with the following properties:
sawine@0
   125
//
sawine@0
   126
//  normalObject        WebGLBuffer object for normals
sawine@0
   127
//  texCoordObject      WebGLBuffer object for texCoords
sawine@0
   128
//  vertexObject        WebGLBuffer object for vertices
sawine@0
   129
//  indexObject         WebGLBuffer object for indices
sawine@0
   130
//  numIndices          The number of indices in the indexObject
sawine@0
   131
// 
sawine@0
   132
function makeBox(ctx)
sawine@0
   133
{
sawine@0
   134
    // box
sawine@0
   135
    //    v6----- v5
sawine@0
   136
    //   /|      /|
sawine@0
   137
    //  v1------v0|
sawine@0
   138
    //  | |     | |
sawine@0
   139
    //  | |v7---|-|v4
sawine@0
   140
    //  |/      |/
sawine@0
   141
    //  v2------v3
sawine@0
   142
    //
sawine@0
   143
    // vertex coords array
sawine@0
   144
    var vertices = new WebGLFloatArray(
sawine@0
   145
        [  1, 1, 1,  -1, 1, 1,  -1,-1, 1,   1,-1, 1,    // v0-v1-v2-v3 front
sawine@0
   146
           1, 1, 1,   1,-1, 1,   1,-1,-1,   1, 1,-1,    // v0-v3-v4-v5 right
sawine@0
   147
           1, 1, 1,   1, 1,-1,  -1, 1,-1,  -1, 1, 1,    // v0-v5-v6-v1 top
sawine@0
   148
          -1, 1, 1,  -1, 1,-1,  -1,-1,-1,  -1,-1, 1,    // v1-v6-v7-v2 left
sawine@0
   149
          -1,-1,-1,   1,-1,-1,   1,-1, 1,  -1,-1, 1,    // v7-v4-v3-v2 bottom
sawine@0
   150
           1,-1,-1,  -1,-1,-1,  -1, 1,-1,   1, 1,-1 ]   // v4-v7-v6-v5 back
sawine@0
   151
    );
sawine@0
   152
sawine@0
   153
    // normal array
sawine@0
   154
    var normals = new WebGLFloatArray(
sawine@0
   155
        [  0, 0, 1,   0, 0, 1,   0, 0, 1,   0, 0, 1,     // v0-v1-v2-v3 front
sawine@0
   156
           1, 0, 0,   1, 0, 0,   1, 0, 0,   1, 0, 0,     // v0-v3-v4-v5 right
sawine@0
   157
           0, 1, 0,   0, 1, 0,   0, 1, 0,   0, 1, 0,     // v0-v5-v6-v1 top
sawine@0
   158
          -1, 0, 0,  -1, 0, 0,  -1, 0, 0,  -1, 0, 0,     // v1-v6-v7-v2 left
sawine@0
   159
           0,-1, 0,   0,-1, 0,   0,-1, 0,   0,-1, 0,     // v7-v4-v3-v2 bottom
sawine@0
   160
           0, 0,-1,   0, 0,-1,   0, 0,-1,   0, 0,-1 ]    // v4-v7-v6-v5 back
sawine@0
   161
       );
sawine@0
   162
sawine@0
   163
sawine@0
   164
    // texCoord array
sawine@0
   165
    var texCoords = new WebGLFloatArray(
sawine@0
   166
        [  1, 1,   0, 1,   0, 0,   1, 0,    // v0-v1-v2-v3 front
sawine@0
   167
           0, 1,   0, 0,   1, 0,   1, 1,    // v0-v3-v4-v5 right
sawine@0
   168
           1, 0,   1, 1,   0, 1,   0, 0,    // v0-v5-v6-v1 top
sawine@0
   169
           1, 1,   0, 1,   0, 0,   1, 0,    // v1-v6-v7-v2 left
sawine@0
   170
           0, 0,   1, 0,   1, 1,   0, 1,    // v7-v4-v3-v2 bottom
sawine@0
   171
           0, 0,   1, 0,   1, 1,   0, 1 ]   // v4-v7-v6-v5 back
sawine@0
   172
       );
sawine@0
   173
sawine@0
   174
    // index array
sawine@0
   175
    var indices = new WebGLUnsignedByteArray(
sawine@0
   176
        [  0, 1, 2,   0, 2, 3,    // front
sawine@0
   177
           4, 5, 6,   4, 6, 7,    // right
sawine@0
   178
           8, 9,10,   8,10,11,    // top
sawine@0
   179
          12,13,14,  12,14,15,    // left
sawine@0
   180
          16,17,18,  16,18,19,    // bottom
sawine@0
   181
          20,21,22,  20,22,23 ]   // back
sawine@0
   182
      );
sawine@0
   183
sawine@0
   184
    var retval = { };
sawine@0
   185
    
sawine@0
   186
    retval.normalObject = ctx.createBuffer();
sawine@0
   187
    ctx.bindBuffer(ctx.ARRAY_BUFFER, retval.normalObject);
sawine@0
   188
    ctx.bufferData(ctx.ARRAY_BUFFER, normals, ctx.STATIC_DRAW);
sawine@0
   189
    
sawine@0
   190
    retval.texCoordObject = ctx.createBuffer();
sawine@0
   191
    ctx.bindBuffer(ctx.ARRAY_BUFFER, retval.texCoordObject);
sawine@0
   192
    ctx.bufferData(ctx.ARRAY_BUFFER, texCoords, ctx.STATIC_DRAW);
sawine@0
   193
sawine@0
   194
    retval.vertexObject = ctx.createBuffer();
sawine@0
   195
    ctx.bindBuffer(ctx.ARRAY_BUFFER, retval.vertexObject);
sawine@0
   196
    ctx.bufferData(ctx.ARRAY_BUFFER, vertices, ctx.STATIC_DRAW);
sawine@0
   197
    
sawine@0
   198
    ctx.bindBuffer(ctx.ARRAY_BUFFER, 0);
sawine@0
   199
sawine@0
   200
    retval.indexObject = ctx.createBuffer();
sawine@0
   201
    ctx.bindBuffer(ctx.ELEMENT_ARRAY_BUFFER, retval.indexObject);
sawine@0
   202
    ctx.bufferData(ctx.ELEMENT_ARRAY_BUFFER, indices, ctx.STATIC_DRAW);
sawine@0
   203
    ctx.bindBuffer(ctx.ELEMENT_ARRAY_BUFFER, 0);
sawine@0
   204
    
sawine@0
   205
    retval.numIndices = indices.length;
sawine@0
   206
sawine@0
   207
    return retval;
sawine@0
   208
}
sawine@0
   209
sawine@0
   210
// 
sawine@0
   211
// makeSphere
sawine@0
   212
//
sawine@0
   213
// Create a sphere with the passed number of latitude and longitude bands and the passed radius. 
sawine@0
   214
// Sphere has vertices, normals and texCoords. Create VBOs for each as well as the index array.
sawine@0
   215
// Return an object with the following properties:
sawine@0
   216
//
sawine@0
   217
//  normalObject        WebGLBuffer object for normals
sawine@0
   218
//  texCoordObject      WebGLBuffer object for texCoords
sawine@0
   219
//  vertexObject        WebGLBuffer object for vertices
sawine@0
   220
//  indexObject         WebGLBuffer object for indices
sawine@0
   221
//  numIndices          The number of indices in the indexObject
sawine@0
   222
// 
sawine@0
   223
function makeSphere(ctx, radius, lats, longs)
sawine@0
   224
{
sawine@0
   225
    var geometryData = [ ];
sawine@0
   226
    var normalData = [ ];
sawine@0
   227
    var texCoordData = [ ];
sawine@0
   228
    var indexData = [ ];
sawine@0
   229
    
sawine@0
   230
    for (var latNumber = 0; latNumber <= lats; ++latNumber) {
sawine@0
   231
        for (var longNumber = 0; longNumber <= longs; ++longNumber) {
sawine@0
   232
            var theta = latNumber * Math.PI / lats;
sawine@0
   233
            var phi = longNumber * 2 * Math.PI / longs;
sawine@0
   234
            var sinTheta = Math.sin(theta);
sawine@0
   235
            var sinPhi = Math.sin(phi);
sawine@0
   236
            var cosTheta = Math.cos(theta);
sawine@0
   237
            var cosPhi = Math.cos(phi);
sawine@0
   238
            
sawine@0
   239
            var x = cosPhi * sinTheta;
sawine@0
   240
            var y = cosTheta;
sawine@0
   241
            var z = sinPhi * sinTheta;
sawine@0
   242
            var u = 1-(longNumber/longs);
sawine@0
   243
            var v = latNumber/lats;
sawine@0
   244
            
sawine@0
   245
            normalData.push(x);
sawine@0
   246
            normalData.push(y);
sawine@0
   247
            normalData.push(z);
sawine@0
   248
            texCoordData.push(u);
sawine@0
   249
            texCoordData.push(v);
sawine@0
   250
            geometryData.push(radius * x);
sawine@0
   251
            geometryData.push(radius * y);
sawine@0
   252
            geometryData.push(radius * z);
sawine@0
   253
        }
sawine@0
   254
    }
sawine@0
   255
    
sawine@0
   256
    longs += 1;
sawine@0
   257
    for (var latNumber = 0; latNumber < lats; ++latNumber) {
sawine@0
   258
        for (var longNumber = 0; longNumber < longs; ++longNumber) {
sawine@0
   259
            var first = (latNumber * longs) + (longNumber % longs);
sawine@0
   260
            var second = first + longs;
sawine@0
   261
            indexData.push(first);
sawine@0
   262
            indexData.push(second);
sawine@0
   263
            indexData.push(first+1);
sawine@0
   264
sawine@0
   265
            indexData.push(second);
sawine@0
   266
            indexData.push(second+1);
sawine@0
   267
            indexData.push(first+1);
sawine@0
   268
        }
sawine@0
   269
    }
sawine@0
   270
    
sawine@0
   271
    var retval = { };
sawine@0
   272
    
sawine@0
   273
    retval.normalObject = ctx.createBuffer();
sawine@0
   274
    ctx.bindBuffer(ctx.ARRAY_BUFFER, retval.normalObject);
sawine@0
   275
    ctx.bufferData(ctx.ARRAY_BUFFER, new WebGLFloatArray(normalData), ctx.STATIC_DRAW);
sawine@0
   276
sawine@0
   277
    retval.texCoordObject = ctx.createBuffer();
sawine@0
   278
    ctx.bindBuffer(ctx.ARRAY_BUFFER, retval.texCoordObject);
sawine@0
   279
    ctx.bufferData(ctx.ARRAY_BUFFER, new WebGLFloatArray(texCoordData), ctx.STATIC_DRAW);
sawine@0
   280
sawine@0
   281
    retval.vertexObject = ctx.createBuffer();
sawine@0
   282
    ctx.bindBuffer(ctx.ARRAY_BUFFER, retval.vertexObject);
sawine@0
   283
    ctx.bufferData(ctx.ARRAY_BUFFER, new WebGLFloatArray(geometryData), ctx.STATIC_DRAW);
sawine@0
   284
    
sawine@0
   285
    retval.numIndices = indexData.length;
sawine@0
   286
    retval.indexObject = ctx.createBuffer();
sawine@0
   287
    ctx.bindBuffer(ctx.ELEMENT_ARRAY_BUFFER, retval.indexObject);
sawine@0
   288
    ctx.bufferData(ctx.ELEMENT_ARRAY_BUFFER, new WebGLUnsignedShortArray(indexData), ctx.STREAM_DRAW);
sawine@0
   289
    
sawine@0
   290
    return retval;
sawine@0
   291
}
sawine@0
   292
sawine@0
   293
//
sawine@0
   294
// loadObj
sawine@0
   295
//
sawine@0
   296
// Load a .obj file from the passed URL. Return an object with a 'loaded' property set to false.
sawine@0
   297
// When the object load is complete, the 'loaded' property becomes true and the following 
sawine@0
   298
// properties are set:
sawine@0
   299
//
sawine@0
   300
//  normalObject        WebGLBuffer object for normals
sawine@0
   301
//  texCoordObject      WebGLBuffer object for texCoords
sawine@0
   302
//  vertexObject        WebGLBuffer object for vertices
sawine@0
   303
//  indexObject         WebGLBuffer object for indices
sawine@0
   304
//  numIndices          The number of indices in the indexObject
sawine@0
   305
//  
sawine@0
   306
function loadObj(ctx, url)
sawine@0
   307
{
sawine@0
   308
    var obj = { loaded : false };
sawine@0
   309
    obj.ctx = ctx;
sawine@0
   310
    var req = new XMLHttpRequest();
sawine@0
   311
    req.obj = obj;
sawine@0
   312
    req.onreadystatechange = function () { processLoadObj(req) };
sawine@0
   313
    req.open("GET", url, true);
sawine@0
   314
    req.send(null);
sawine@0
   315
    return obj;
sawine@0
   316
}
sawine@0
   317
sawine@0
   318
function processLoadObj(req) 
sawine@0
   319
{
sawine@0
   320
    console.log("req="+req)
sawine@0
   321
    // only if req shows "complete"
sawine@0
   322
    if (req.readyState == 4) {
sawine@0
   323
        doLoadObj(req.obj, req.responseText);
sawine@0
   324
    }
sawine@0
   325
}
sawine@0
   326
sawine@0
   327
function doLoadObj(obj, text)
sawine@0
   328
{
sawine@0
   329
    vertexArray = [ ];
sawine@0
   330
    normalArray = [ ];
sawine@0
   331
    textureArray = [ ];
sawine@0
   332
    indexArray = [ ];
sawine@0
   333
    
sawine@0
   334
    var vertex = [ ];
sawine@0
   335
    var normal = [ ];
sawine@0
   336
    var texture = [ ];
sawine@0
   337
    var facemap = { };
sawine@0
   338
    var index = 0;
sawine@0
   339
        
sawine@0
   340
    var lines = text.split("\n");
sawine@0
   341
    for (var lineIndex in lines) {
sawine@0
   342
        var line = lines[lineIndex].replace(/[ \t]+/g, " ").replace(/\s\s*$/, "");
sawine@0
   343
        
sawine@0
   344
        // ignore comments
sawine@0
   345
        if (line[0] == "#")
sawine@0
   346
            continue;
sawine@0
   347
            
sawine@0
   348
        var array = line.split(" ");
sawine@0
   349
        if (array[0] == "v") {
sawine@0
   350
            // vertex
sawine@0
   351
            vertex.push(parseFloat(array[1]));
sawine@0
   352
            vertex.push(parseFloat(array[2]));
sawine@0
   353
            vertex.push(parseFloat(array[3]));
sawine@0
   354
        }
sawine@0
   355
        else if (array[0] == "vt") {
sawine@0
   356
            // normal
sawine@0
   357
            texture.push(parseFloat(array[1]));
sawine@0
   358
            texture.push(parseFloat(array[2]));
sawine@0
   359
        }
sawine@0
   360
        else if (array[0] == "vn") {
sawine@0
   361
            // normal
sawine@0
   362
            normal.push(parseFloat(array[1]));
sawine@0
   363
            normal.push(parseFloat(array[2]));
sawine@0
   364
            normal.push(parseFloat(array[3]));
sawine@0
   365
        }
sawine@0
   366
        else if (array[0] == "f") {
sawine@0
   367
            // face
sawine@0
   368
            if (array.length != 4) {
sawine@0
   369
                console.log("*** Error: face '"+line+"' not handled");
sawine@0
   370
                continue;
sawine@0
   371
            }
sawine@0
   372
            
sawine@0
   373
            for (var i = 1; i < 4; ++i) {
sawine@0
   374
                if (!(array[i] in facemap)) {
sawine@0
   375
                    // add a new entry to the map and arrays
sawine@0
   376
                    var f = array[i].split("/");
sawine@0
   377
                    var vtx, nor, tex;
sawine@0
   378
                    
sawine@0
   379
                    if (f.length == 1) {
sawine@0
   380
                        vtx = parseInt(f[0]) - 1;
sawine@0
   381
                        nor = vtx;
sawine@0
   382
                        tex = vtx;
sawine@0
   383
                    }
sawine@0
   384
                    else if (f.length = 3) {
sawine@0
   385
                        vtx = parseInt(f[0]) - 1;
sawine@0
   386
                        tex = parseInt(f[1]) - 1;
sawine@0
   387
                        nor = parseInt(f[2]) - 1;
sawine@0
   388
                    }
sawine@0
   389
                    else {
sawine@0
   390
                        console.log("*** Error: did not understand face '"+array[i]+"'");
sawine@0
   391
                        return null;
sawine@0
   392
                    }
sawine@0
   393
                    
sawine@0
   394
                    // do the vertices
sawine@0
   395
                    var x = 0;
sawine@0
   396
                    var y = 0;
sawine@0
   397
                    var z = 0;
sawine@0
   398
                    if (vtx * 3 + 2 < vertex.length) {
sawine@0
   399
                        x = vertex[vtx*3];
sawine@0
   400
                        y = vertex[vtx*3+1];
sawine@0
   401
                        z = vertex[vtx*3+2];
sawine@0
   402
                    }
sawine@0
   403
                    vertexArray.push(x);
sawine@0
   404
                    vertexArray.push(y);
sawine@0
   405
                    vertexArray.push(z);
sawine@0
   406
                    
sawine@0
   407
                    // do the textures
sawine@0
   408
                    x = 0;
sawine@0
   409
                    y = 0;
sawine@0
   410
                    if (tex * 2 + 1 < texture.length) {
sawine@0
   411
                        x = texture[tex*2];
sawine@0
   412
                        y = texture[tex*2+1];
sawine@0
   413
                    }
sawine@0
   414
                    textureArray.push(x);
sawine@0
   415
                    textureArray.push(y);
sawine@0
   416
                    
sawine@0
   417
                    // do the normals
sawine@0
   418
                    x = 0;
sawine@0
   419
                    y = 0;
sawine@0
   420
                    z = 1;
sawine@0
   421
                    if (nor * 3 + 2 < normal.length) {
sawine@0
   422
                        x = normal[nor*3];
sawine@0
   423
                        y = normal[nor*3+1];
sawine@0
   424
                        z = normal[nor*3+2];
sawine@0
   425
                    }
sawine@0
   426
                    normalArray.push(x);
sawine@0
   427
                    normalArray.push(y);
sawine@0
   428
                    normalArray.push(z);
sawine@0
   429
                    
sawine@0
   430
                    facemap[array[i]] = index++;
sawine@0
   431
                }
sawine@0
   432
                
sawine@0
   433
                indexArray.push(facemap[array[i]]);
sawine@0
   434
            }
sawine@0
   435
        }
sawine@0
   436
    }
sawine@0
   437
sawine@0
   438
    // set the VBOs
sawine@0
   439
    obj.normalObject = obj.ctx.createBuffer();
sawine@0
   440
    obj.ctx.bindBuffer(obj.ctx.ARRAY_BUFFER, obj.normalObject);
sawine@0
   441
    obj.ctx.bufferData(obj.ctx.ARRAY_BUFFER, new WebGLFloatArray(normalArray), obj.ctx.STATIC_DRAW);
sawine@0
   442
sawine@0
   443
    obj.texCoordObject = obj.ctx.createBuffer();
sawine@0
   444
    obj.ctx.bindBuffer(obj.ctx.ARRAY_BUFFER, obj.texCoordObject);
sawine@0
   445
    obj.ctx.bufferData(obj.ctx.ARRAY_BUFFER, new WebGLFloatArray(textureArray), obj.ctx.STATIC_DRAW);
sawine@0
   446
sawine@0
   447
    obj.vertexObject = obj.ctx.createBuffer();
sawine@0
   448
    obj.ctx.bindBuffer(obj.ctx.ARRAY_BUFFER, obj.vertexObject);
sawine@0
   449
    obj.ctx.bufferData(obj.ctx.ARRAY_BUFFER, new WebGLFloatArray(vertexArray), obj.ctx.STATIC_DRAW);
sawine@0
   450
    
sawine@0
   451
    obj.numIndices = indexArray.length;
sawine@0
   452
    obj.indexObject = obj.ctx.createBuffer();
sawine@0
   453
    obj.ctx.bindBuffer(obj.ctx.ELEMENT_ARRAY_BUFFER, obj.indexObject);
sawine@0
   454
    obj.ctx.bufferData(obj.ctx.ELEMENT_ARRAY_BUFFER, new WebGLUnsignedShortArray(indexArray), obj.ctx.STREAM_DRAW);
sawine@0
   455
    
sawine@0
   456
    obj.loaded = true;
sawine@0
   457
}
sawine@0
   458
sawine@0
   459
//
sawine@0
   460
// loadImageTexture
sawine@0
   461
//
sawine@0
   462
// Load the image at the passed url, place it in a new WebGLTexture object and return the WebGLTexture.
sawine@0
   463
//
sawine@0
   464
function loadImageTexture(ctx, url)
sawine@0
   465
{
sawine@0
   466
    var texture = ctx.createTexture();
sawine@0
   467
    texture.image = new Image();
sawine@0
   468
    texture.image.onload = function() { doLoadImageTexture(ctx, texture.image, texture) }
sawine@0
   469
    texture.image.src = url;
sawine@0
   470
    return texture;
sawine@0
   471
}
sawine@0
   472
sawine@0
   473
function doLoadImageTexture(ctx, image, texture)
sawine@0
   474
{
sawine@0
   475
    ctx.enable(ctx.TEXTURE_2D);
sawine@0
   476
    ctx.bindTexture(ctx.TEXTURE_2D, texture);
sawine@0
   477
    ctx.texImage2D(ctx.TEXTURE_2D, 0, image);
sawine@0
   478
    ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_MAG_FILTER, ctx.LINEAR);
sawine@0
   479
    ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_MIN_FILTER, ctx.LINEAR_MIPMAP_LINEAR);
sawine@0
   480
    ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_WRAP_S, ctx.CLAMP_TO_EDGE);
sawine@0
   481
    ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_WRAP_T, ctx.CLAMP_TO_EDGE);
sawine@0
   482
    ctx.generateMipmap(ctx.TEXTURE_2D)
sawine@0
   483
    ctx.bindTexture(ctx.TEXTURE_2D, 0);
sawine@0
   484
}
sawine@0
   485
sawine@0
   486
//
sawine@0
   487
// Framerate object
sawine@0
   488
//
sawine@0
   489
// This object keeps track of framerate and displays it as the innerHTML text of the 
sawine@0
   490
// HTML element with the passed id. Once created you call snapshot at the end
sawine@0
   491
// of every rendering cycle. Every 500ms the framerate is updated in the HTML element.
sawine@0
   492
//
sawine@0
   493
Framerate = function(id)
sawine@0
   494
{
sawine@0
   495
    this.numFramerates = 10;
sawine@0
   496
    this.framerateUpdateInterval = 500;
sawine@0
   497
    this.id = id;
sawine@0
   498
sawine@0
   499
    this.renderTime = -1;
sawine@0
   500
    this.framerates = [ ];
sawine@0
   501
    self = this;
sawine@0
   502
    var fr = function() { self.updateFramerate() }
sawine@0
   503
    setInterval(fr, this.framerateUpdateInterval);
sawine@0
   504
}
sawine@0
   505
sawine@0
   506
Framerate.prototype.updateFramerate = function()
sawine@0
   507
{
sawine@0
   508
    var tot = 0;
sawine@0
   509
    for (var i = 0; i < this.framerates.length; ++i)
sawine@0
   510
        tot += this.framerates[i];
sawine@0
   511
        
sawine@0
   512
    var framerate = tot / this.framerates.length;
sawine@0
   513
    framerate = Math.round(framerate);
sawine@0
   514
    document.getElementById(this.id).innerHTML = "Framerate:"+framerate+"fps";
sawine@0
   515
}
sawine@0
   516
sawine@0
   517
Framerate.prototype.snapshot = function()
sawine@0
   518
{
sawine@0
   519
    if (this.renderTime < 0)
sawine@0
   520
        this.renderTime = new Date().getTime();
sawine@0
   521
    else {
sawine@0
   522
        var newTime = new Date().getTime();
sawine@0
   523
        var t = newTime - this.renderTime;
sawine@0
   524
        var framerate = 1000/t;
sawine@0
   525
        this.framerates.push(framerate);
sawine@0
   526
        while (this.framerates.length > this.numFramerates)
sawine@0
   527
            this.framerates.shift();
sawine@0
   528
        this.renderTime = newTime;
sawine@0
   529
    }
sawine@0
   530
}