content/canvas/test/webgl-conformance/conformance/resources/webgl-test.js

Thu, 15 Jan 2015 21:03:48 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 21:03:48 +0100
branch
TOR_BUG_9701
changeset 11
deefc01c0e14
permissions
-rw-r--r--

Integrate friendly tips from Tor colleagues to make (or not) 4.5 alpha 3;
This includes removal of overloaded (but unused) methods, and addition of
a overlooked call to DataStruct::SetData(nsISupports, uint32_t, bool.)

     1 /*
     2 Copyright (C) 2011 Apple Computer, Inc.  All rights reserved.
     4 Redistribution and use in source and binary forms, with or without
     5 modification, are permitted provided that the following conditions
     6 are met:
     7 1. Redistributions of source code must retain the above copyright
     8    notice, this list of conditions and the following disclaimer.
     9 2. Redistributions in binary form must reproduce the above copyright
    10    notice, this list of conditions and the following disclaimer in the
    11    documentation and/or other materials provided with the distribution.
    13 THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
    14 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    15 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
    16 PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
    17 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
    18 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
    19 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
    20 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
    21 OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    22 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    23 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    24 */
    26 function webglTestLog(msg) {
    27   if (window.console && window.console.log) {
    28     window.console.log(msg);
    29   }
    30   if (document.getElementById("console")) {
    31     var log = document.getElementById("console");
    32     log.innerHTML += msg + "<br>";
    33   }
    34 }
    36 //
    37 // create3DContext
    38 //
    39 // Returns the WebGLRenderingContext for any known implementation.
    40 //
    41 function create3DContext(canvas, attributes)
    42 {
    43     if (!canvas)
    44         canvas = document.createElement("canvas");
    45     var names = ["webgl", "experimental-webgl"];
    46     var context = null;
    47     for (var i = 0; i < names.length; ++i) {
    48       try {
    49         context = canvas.getContext(names[i], attributes);
    50       } catch (e) {
    51       }
    52       if (context) {
    53         break;
    54       }
    55     }
    56     if (!context) {
    57         throw "Unable to fetch WebGL rendering context for Canvas";
    58     }
    59     return context;
    60 }
    62 function createGLErrorWrapper(context, fname) {
    63     return function() {
    64         var rv = context[fname].apply(context, arguments);
    65         var err = context.getError();
    66         if (err != 0)
    67             throw "GL error " + err + " in " + fname;
    68         return rv;
    69     };
    70 }
    72 function create3DContextWithWrapperThatThrowsOnGLError(canvas, attributes) {
    73   var context = create3DContext(canvas, attributes);
    74   // Thanks to Ilmari Heikkinen for the idea on how to implement this so elegantly.
    75   var wrap = {};
    76   for (var i in context) {
    77     try {
    78       if (typeof context[i] == 'function') {
    79         wrap[i] = createGLErrorWrapper(context, i);
    80       } else {
    81         wrap[i] = context[i];
    82       }
    83     } catch (e) {
    84       webglTestLog("createContextWrapperThatThrowsOnGLError: Error accessing " + i);
    85     }
    86   }
    87   wrap.getError = function() {
    88       return context.getError();
    89   };
    90   return wrap;
    91 }
    93 function getGLErrorAsString(ctx, err) {
    94   if (err === ctx.NO_ERROR) {
    95     return "NO_ERROR";
    96   }
    97   for (var name in ctx) {
    98     if (ctx[name] === err) {
    99       return name;
   100     }
   101   }
   102   return "0x" + err.toString(16);
   103 }
   105 // Pass undefined for glError to test that it at least throws some error
   106 function shouldGenerateGLError(ctx, glErrors, evalStr) {
   107   if (!glErrors.length) {
   108     glErrors = [glErrors];
   109   }
   110   var exception;
   111   try {
   112     eval(evalStr);
   113   } catch (e) {
   114     exception = e;
   115   }
   116   if (exception) {
   117     testFailed(evalStr + " threw exception " + exception);
   118   } else {
   119     var err = ctx.getError();
   120     if (glErrors.indexOf(err) < 0) {
   121       var errStrs = [];
   122       for (var ii = 0; ii < glErrors.length; ++ii) {
   123         errStrs.push(getGLErrorAsString(ctx, glErrors[ii]));
   124       }
   125       testFailed(evalStr + " expected: " + errStrs.join(" or ") + ". Was " + getGLErrorAsString(ctx, err) + ".");
   126     } else {
   127       testPassed(evalStr + " generated expected GL error: " + getGLErrorAsString(ctx, err) + ".");
   128     }
   129   }
   130 }
   132 /**
   133  * Tests that the first error GL returns is the specified error.
   134  * @param {!WebGLContext} gl The WebGLContext to use.
   135  * @param {number|!Array.<number>} glError The expected gl
   136  *        error. Multiple errors can be passed in using an
   137  *        array.
   138  * @param {string} opt_msg Optional additional message.
   139  */
   140 function glErrorShouldBe(gl, glErrors, opt_msg) {
   141   if (!glErrors.length) {
   142     glErrors = [glErrors];
   143   }
   144   opt_msg = opt_msg || "";
   145   var err = gl.getError();
   146   var ndx = glErrors.indexOf(err);
   147   if (ndx < 0) {
   148     if (glErrors.length == 1) {
   149       testFailed("getError expected: " + getGLErrorAsString(gl, glErrors[0]) +
   150                  ". Was " + getGLErrorAsString(gl, err) + " : " + opt_msg);
   151     } else {
   152       var errs = [];
   153       for (var ii = 0; ii < glErrors.length; ++ii) {
   154         errs.push(getGLErrorAsString(gl, glErrors[ii]));
   155       }
   156       testFailed("getError expected one of: [" + errs.join(", ") +
   157                  "]. Was " + getGLErrorAsString(gl, err) + " : " + opt_msg);
   158     }
   159   } else {
   160     testPassed("getError was expected value: " +
   161                 getGLErrorAsString(gl, err) + " : " + opt_msg);
   162   }
   163 };
   165 //
   166 // createProgram
   167 //
   168 // Create and return a program object, attaching each of the given shaders.
   169 //
   170 // If attribs are given, bind an attrib with that name at that index.
   171 //
   172 function createProgram(gl, vshaders, fshaders, attribs)
   173 {
   174   if (typeof(vshaders) == "string")
   175     vshaders = [vshaders];
   176   if (typeof(fshaders) == "string")
   177     fshaders = [fshaders];
   179   var shaders = [];
   180   var i;
   182   for (i = 0; i < vshaders.length; ++i) {
   183     var shader = loadShader(gl, vshaders[i], gl.VERTEX_SHADER);
   184     if (!shader)
   185       return null;
   186     shaders.push(shader);
   187   }
   189   for (i = 0; i < fshaders.length; ++i) {
   190     var shader = loadShader(gl, fshaders[i], gl.FRAGMENT_SHADER);
   191     if (!shader)
   192       return null;
   193     shaders.push(shader);
   194   }
   196   var prog = gl.createProgram();
   197   for (i = 0; i < shaders.length; ++i) {
   198     gl.attachShader(prog, shaders[i]);
   199   }
   201   if (attribs) {
   202     for (var i = 0; i < attribs.length; ++i) {
   203       gl.bindAttribLocation(prog, i, attribs[i]);
   204     }
   205   }
   207   gl.linkProgram(prog);
   209   // Check the link status
   210   var linked = gl.getProgramParameter(prog, gl.LINK_STATUS);
   211   if (!linked) {
   212     // something went wrong with the link
   213     var error = gl.getProgramInfoLog(prog);
   214     webglTestLog("Error in program linking:" + error);
   216     gl.deleteProgram(prog);
   217     for (i = 0; i < shaders.length; ++i)
   218       gl.deleteShader(shaders[i]);
   219     return null;
   220   }
   222   return prog;
   223 }
   225 //
   226 // initWebGL
   227 //
   228 // Initialize the Canvas element with the passed name as a WebGL object and return the
   229 // WebGLRenderingContext.
   230 //
   231 // Load shaders with the passed names and create a program with them. Return this program
   232 // in the 'program' property of the returned context.
   233 //
   234 // For each string in the passed attribs array, bind an attrib with that name at that index.
   235 // Once the attribs are bound, link the program and then use it.
   236 //
   237 // Set the clear color to the passed array (4 values) and set the clear depth to the passed value.
   238 // Enable depth testing and blending with a blend func of (SRC_ALPHA, ONE_MINUS_SRC_ALPHA)
   239 //
   240 function initWebGL(canvasName, vshader, fshader, attribs, clearColor, clearDepth, contextAttribs)
   241 {
   242     var canvas = document.getElementById(canvasName);
   243     var gl = create3DContext(canvas, contextAttribs);
   244     if (!gl) {
   245         alert("No WebGL context found");
   246         return null;
   247     }
   249     // Create the program object
   250     gl.program = createProgram(gl, vshader, fshader, attribs);
   251     if (!gl.program)
   252         return null;
   254     gl.useProgram(gl.program);
   256     gl.clearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]);
   257     gl.clearDepth(clearDepth);
   259     gl.enable(gl.DEPTH_TEST);
   260     gl.enable(gl.BLEND);
   261     gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
   263     return gl;
   264 }
   266 //
   267 // getShaderSource
   268 //
   269 // Load the source from the passed shader file.
   270 //
   271 function getShaderSource(file)
   272 {
   273     var xhr = new XMLHttpRequest();
   274     xhr.open("GET", file, false);
   275     xhr.send();
   276     return xhr.responseText;
   277 }
   280 //
   281 // loadShader
   282 //
   283 // 'shader' is either the id of a <script> element containing the shader source
   284 // string, the shader string itself,  or the URL of a file containing the shader
   285 // source. Load this shader and return the WebGLShader object corresponding to
   286 // it.
   287 //
   288 function loadShader(ctx, shaderId, shaderType, isFile)
   289 {
   290     var shaderSource = "";
   292     if (isFile)
   293         shaderSource = getShaderSource(shaderId);
   294     else {
   295         var shaderScript = document.getElementById(shaderId);
   296         if (!shaderScript) {
   297             shaderSource = shaderId;
   298         } else {
   299             if (shaderScript.type == "x-shader/x-vertex") {
   300                 shaderType = ctx.VERTEX_SHADER;
   301             } else if (shaderScript.type == "x-shader/x-fragment") {
   302                 shaderType = ctx.FRAGMENT_SHADER;
   303             } else if (shaderType != ctx.VERTEX_SHADER && shaderType != ctx.FRAGMENT_SHADER) {
   304                 webglTestLog("*** Error: unknown shader type");
   305                 return null;
   306             }
   308             shaderSource = shaderScript.text;
   309         }
   310     }
   312     // Create the shader object
   313     var shader = ctx.createShader(shaderType);
   314     if (shader == null) {
   315         webglTestLog("*** Error: unable to create shader '"+shaderId+"'");
   316         return null;
   317     }
   319     // Load the shader source
   320     ctx.shaderSource(shader, shaderSource);
   322     // Compile the shader
   323     ctx.compileShader(shader);
   325     // Check the compile status
   326     var compiled = ctx.getShaderParameter(shader, ctx.COMPILE_STATUS);
   327     if (!compiled) {
   328         // Something went wrong during compilation; get the error
   329         var error = ctx.getShaderInfoLog(shader);
   330         webglTestLog("*** Error compiling shader '"+shader+"':"+error);
   331         ctx.deleteShader(shader);
   332         return null;
   333     }
   335     return shader;
   336 }
   338 function loadShaderFromFile(ctx, file, type)
   339 {
   340     return loadShader(ctx, file, type, true);
   341 }
   343 function loadShaderFromScript(ctx, script)
   344 {
   345     return loadShader(ctx, script, 0, false);
   346 }
   348 function loadStandardProgram(context) {
   349     var program = context.createProgram();
   350     context.attachShader(program, loadStandardVertexShader(context));
   351     context.attachShader(program, loadStandardFragmentShader(context));
   352     context.linkProgram(program);
   353     return program;
   354 }
   356 function loadProgram(context, vertexShaderPath, fragmentShaderPath, isFile) {
   357     isFile = (isFile === undefined) ? true : isFile;
   358     var program = context.createProgram();
   359     context.attachShader(program, loadShader(context, vertexShaderPath, context.VERTEX_SHADER, isFile));
   360     context.attachShader(program, loadShader(context, fragmentShaderPath, context.FRAGMENT_SHADER, isFile));
   361     context.linkProgram(program);
   362     return program;
   363 }
   365 var getBasePathForResources = function() {
   366   var expectedBase = "webgl-test.js";
   367   var scripts = document.getElementsByTagName('script');
   368   for (var script, i = 0; script = scripts[i]; i++) {
   369     var src = script.src;
   370     var l = src.length;
   371     if (src.substr(l - expectedBase.length) == expectedBase) {
   372       return src.substr(0, l - expectedBase.length);
   373     }
   374   }
   375   throw 'oops';
   376 };
   379 function loadStandardVertexShader(context) {
   380     return loadShader(
   381         context,
   382         getBasePathForResources() + "vertexShader.vert",
   383         context.VERTEX_SHADER,
   384         true);
   385 }
   387 function loadStandardFragmentShader(context) {
   388     return loadShader(
   389         context,
   390         getBasePathForResources() + "fragmentShader.frag",
   391         context.FRAGMENT_SHADER,
   392         true);
   393 }
   395 //
   396 // makeBox
   397 //
   398 // Create a box with vertices, normals and texCoords. Create VBOs for each as well as the index array.
   399 // Return an object with the following properties:
   400 //
   401 //  normalObject        WebGLBuffer object for normals
   402 //  texCoordObject      WebGLBuffer object for texCoords
   403 //  vertexObject        WebGLBuffer object for vertices
   404 //  indexObject         WebGLBuffer object for indices
   405 //  numIndices          The number of indices in the indexObject
   406 //
   407 function makeBox(ctx)
   408 {
   409     // box
   410     //    v6----- v5
   411     //   /|      /|
   412     //  v1------v0|
   413     //  | |     | |
   414     //  | |v7---|-|v4
   415     //  |/      |/
   416     //  v2------v3
   417     //
   418     // vertex coords array
   419     var vertices = new Float32Array(
   420         [  1, 1, 1,  -1, 1, 1,  -1,-1, 1,   1,-1, 1,    // v0-v1-v2-v3 front
   421            1, 1, 1,   1,-1, 1,   1,-1,-1,   1, 1,-1,    // v0-v3-v4-v5 right
   422            1, 1, 1,   1, 1,-1,  -1, 1,-1,  -1, 1, 1,    // v0-v5-v6-v1 top
   423           -1, 1, 1,  -1, 1,-1,  -1,-1,-1,  -1,-1, 1,    // v1-v6-v7-v2 left
   424           -1,-1,-1,   1,-1,-1,   1,-1, 1,  -1,-1, 1,    // v7-v4-v3-v2 bottom
   425            1,-1,-1,  -1,-1,-1,  -1, 1,-1,   1, 1,-1 ]   // v4-v7-v6-v5 back
   426     );
   428     // normal array
   429     var normals = new Float32Array(
   430         [  0, 0, 1,   0, 0, 1,   0, 0, 1,   0, 0, 1,     // v0-v1-v2-v3 front
   431            1, 0, 0,   1, 0, 0,   1, 0, 0,   1, 0, 0,     // v0-v3-v4-v5 right
   432            0, 1, 0,   0, 1, 0,   0, 1, 0,   0, 1, 0,     // v0-v5-v6-v1 top
   433           -1, 0, 0,  -1, 0, 0,  -1, 0, 0,  -1, 0, 0,     // v1-v6-v7-v2 left
   434            0,-1, 0,   0,-1, 0,   0,-1, 0,   0,-1, 0,     // v7-v4-v3-v2 bottom
   435            0, 0,-1,   0, 0,-1,   0, 0,-1,   0, 0,-1 ]    // v4-v7-v6-v5 back
   436        );
   439     // texCoord array
   440     var texCoords = new Float32Array(
   441         [  1, 1,   0, 1,   0, 0,   1, 0,    // v0-v1-v2-v3 front
   442            0, 1,   0, 0,   1, 0,   1, 1,    // v0-v3-v4-v5 right
   443            1, 0,   1, 1,   0, 1,   0, 0,    // v0-v5-v6-v1 top
   444            1, 1,   0, 1,   0, 0,   1, 0,    // v1-v6-v7-v2 left
   445            0, 0,   1, 0,   1, 1,   0, 1,    // v7-v4-v3-v2 bottom
   446            0, 0,   1, 0,   1, 1,   0, 1 ]   // v4-v7-v6-v5 back
   447        );
   449     // index array
   450     var indices = new Uint8Array(
   451         [  0, 1, 2,   0, 2, 3,    // front
   452            4, 5, 6,   4, 6, 7,    // right
   453            8, 9,10,   8,10,11,    // top
   454           12,13,14,  12,14,15,    // left
   455           16,17,18,  16,18,19,    // bottom
   456           20,21,22,  20,22,23 ]   // back
   457       );
   459     var retval = { };
   461     retval.normalObject = ctx.createBuffer();
   462     ctx.bindBuffer(ctx.ARRAY_BUFFER, retval.normalObject);
   463     ctx.bufferData(ctx.ARRAY_BUFFER, normals, ctx.STATIC_DRAW);
   465     retval.texCoordObject = ctx.createBuffer();
   466     ctx.bindBuffer(ctx.ARRAY_BUFFER, retval.texCoordObject);
   467     ctx.bufferData(ctx.ARRAY_BUFFER, texCoords, ctx.STATIC_DRAW);
   469     retval.vertexObject = ctx.createBuffer();
   470     ctx.bindBuffer(ctx.ARRAY_BUFFER, retval.vertexObject);
   471     ctx.bufferData(ctx.ARRAY_BUFFER, vertices, ctx.STATIC_DRAW);
   473     ctx.bindBuffer(ctx.ARRAY_BUFFER, 0);
   475     retval.indexObject = ctx.createBuffer();
   476     ctx.bindBuffer(ctx.ELEMENT_ARRAY_BUFFER, retval.indexObject);
   477     ctx.bufferData(ctx.ELEMENT_ARRAY_BUFFER, indices, ctx.STATIC_DRAW);
   478     ctx.bindBuffer(ctx.ELEMENT_ARRAY_BUFFER, 0);
   480     retval.numIndices = indices.length;
   482     return retval;
   483 }
   485 //
   486 // makeSphere
   487 //
   488 // Create a sphere with the passed number of latitude and longitude bands and the passed radius.
   489 // Sphere has vertices, normals and texCoords. Create VBOs for each as well as the index array.
   490 // Return an object with the following properties:
   491 //
   492 //  normalObject        WebGLBuffer object for normals
   493 //  texCoordObject      WebGLBuffer object for texCoords
   494 //  vertexObject        WebGLBuffer object for vertices
   495 //  indexObject         WebGLBuffer object for indices
   496 //  numIndices          The number of indices in the indexObject
   497 //
   498 function makeSphere(ctx, radius, lats, longs)
   499 {
   500     var geometryData = [ ];
   501     var normalData = [ ];
   502     var texCoordData = [ ];
   503     var indexData = [ ];
   505     for (var latNumber = 0; latNumber <= lats; ++latNumber) {
   506         for (var longNumber = 0; longNumber <= longs; ++longNumber) {
   507             var theta = latNumber * Math.PI / lats;
   508             var phi = longNumber * 2 * Math.PI / longs;
   509             var sinTheta = Math.sin(theta);
   510             var sinPhi = Math.sin(phi);
   511             var cosTheta = Math.cos(theta);
   512             var cosPhi = Math.cos(phi);
   514             var x = cosPhi * sinTheta;
   515             var y = cosTheta;
   516             var z = sinPhi * sinTheta;
   517             var u = 1-(longNumber/longs);
   518             var v = latNumber/lats;
   520             normalData.push(x);
   521             normalData.push(y);
   522             normalData.push(z);
   523             texCoordData.push(u);
   524             texCoordData.push(v);
   525             geometryData.push(radius * x);
   526             geometryData.push(radius * y);
   527             geometryData.push(radius * z);
   528         }
   529     }
   531     longs += 1;
   532     for (var latNumber = 0; latNumber < lats; ++latNumber) {
   533         for (var longNumber = 0; longNumber < longs; ++longNumber) {
   534             var first = (latNumber * longs) + (longNumber % longs);
   535             var second = first + longs;
   536             indexData.push(first);
   537             indexData.push(second);
   538             indexData.push(first+1);
   540             indexData.push(second);
   541             indexData.push(second+1);
   542             indexData.push(first+1);
   543         }
   544     }
   546     var retval = { };
   548     retval.normalObject = ctx.createBuffer();
   549     ctx.bindBuffer(ctx.ARRAY_BUFFER, retval.normalObject);
   550     ctx.bufferData(ctx.ARRAY_BUFFER, new Float32Array(normalData), ctx.STATIC_DRAW);
   552     retval.texCoordObject = ctx.createBuffer();
   553     ctx.bindBuffer(ctx.ARRAY_BUFFER, retval.texCoordObject);
   554     ctx.bufferData(ctx.ARRAY_BUFFER, new Float32Array(texCoordData), ctx.STATIC_DRAW);
   556     retval.vertexObject = ctx.createBuffer();
   557     ctx.bindBuffer(ctx.ARRAY_BUFFER, retval.vertexObject);
   558     ctx.bufferData(ctx.ARRAY_BUFFER, new Float32Array(geometryData), ctx.STATIC_DRAW);
   560     retval.numIndices = indexData.length;
   561     retval.indexObject = ctx.createBuffer();
   562     ctx.bindBuffer(ctx.ELEMENT_ARRAY_BUFFER, retval.indexObject);
   563     ctx.bufferData(ctx.ELEMENT_ARRAY_BUFFER, new Uint16Array(indexData), ctx.STREAM_DRAW);
   565     return retval;
   566 }
   568 //
   569 // loadObj
   570 //
   571 // Load a .obj file from the passed URL. Return an object with a 'loaded' property set to false.
   572 // When the object load is complete, the 'loaded' property becomes true and the following
   573 // properties are set:
   574 //
   575 //  normalObject        WebGLBuffer object for normals
   576 //  texCoordObject      WebGLBuffer object for texCoords
   577 //  vertexObject        WebGLBuffer object for vertices
   578 //  indexObject         WebGLBuffer object for indices
   579 //  numIndices          The number of indices in the indexObject
   580 //
   581 function loadObj(ctx, url)
   582 {
   583     var obj = { loaded : false };
   584     obj.ctx = ctx;
   585     var req = new XMLHttpRequest();
   586     req.obj = obj;
   587     req.onreadystatechange = function () { processLoadObj(req) };
   588     req.open("GET", url, true);
   589     req.send(null);
   590     return obj;
   591 }
   593 function processLoadObj(req)
   594 {
   595     webglTestLog("req="+req)
   596     // only if req shows "complete"
   597     if (req.readyState == 4) {
   598         doLoadObj(req.obj, req.responseText);
   599     }
   600 }
   602 function doLoadObj(obj, text)
   603 {
   604     vertexArray = [ ];
   605     normalArray = [ ];
   606     textureArray = [ ];
   607     indexArray = [ ];
   609     var vertex = [ ];
   610     var normal = [ ];
   611     var texture = [ ];
   612     var facemap = { };
   613     var index = 0;
   615     var lines = text.split("\n");
   616     for (var lineIndex in lines) {
   617         var line = lines[lineIndex].replace(/[ \t]+/g, " ").replace(/\s\s*$/, "");
   619         // ignore comments
   620         if (line[0] == "#")
   621             continue;
   623         var array = line.split(" ");
   624         if (array[0] == "v") {
   625             // vertex
   626             vertex.push(parseFloat(array[1]));
   627             vertex.push(parseFloat(array[2]));
   628             vertex.push(parseFloat(array[3]));
   629         }
   630         else if (array[0] == "vt") {
   631             // normal
   632             texture.push(parseFloat(array[1]));
   633             texture.push(parseFloat(array[2]));
   634         }
   635         else if (array[0] == "vn") {
   636             // normal
   637             normal.push(parseFloat(array[1]));
   638             normal.push(parseFloat(array[2]));
   639             normal.push(parseFloat(array[3]));
   640         }
   641         else if (array[0] == "f") {
   642             // face
   643             if (array.length != 4) {
   644                 webglTestLog("*** Error: face '"+line+"' not handled");
   645                 continue;
   646             }
   648             for (var i = 1; i < 4; ++i) {
   649                 if (!(array[i] in facemap)) {
   650                     // add a new entry to the map and arrays
   651                     var f = array[i].split("/");
   652                     var vtx, nor, tex;
   654                     if (f.length == 1) {
   655                         vtx = parseInt(f[0]) - 1;
   656                         nor = vtx;
   657                         tex = vtx;
   658                     }
   659                     else if (f.length = 3) {
   660                         vtx = parseInt(f[0]) - 1;
   661                         tex = parseInt(f[1]) - 1;
   662                         nor = parseInt(f[2]) - 1;
   663                     }
   664                     else {
   665                         webglTestLog("*** Error: did not understand face '"+array[i]+"'");
   666                         return null;
   667                     }
   669                     // do the vertices
   670                     var x = 0;
   671                     var y = 0;
   672                     var z = 0;
   673                     if (vtx * 3 + 2 < vertex.length) {
   674                         x = vertex[vtx*3];
   675                         y = vertex[vtx*3+1];
   676                         z = vertex[vtx*3+2];
   677                     }
   678                     vertexArray.push(x);
   679                     vertexArray.push(y);
   680                     vertexArray.push(z);
   682                     // do the textures
   683                     x = 0;
   684                     y = 0;
   685                     if (tex * 2 + 1 < texture.length) {
   686                         x = texture[tex*2];
   687                         y = texture[tex*2+1];
   688                     }
   689                     textureArray.push(x);
   690                     textureArray.push(y);
   692                     // do the normals
   693                     x = 0;
   694                     y = 0;
   695                     z = 1;
   696                     if (nor * 3 + 2 < normal.length) {
   697                         x = normal[nor*3];
   698                         y = normal[nor*3+1];
   699                         z = normal[nor*3+2];
   700                     }
   701                     normalArray.push(x);
   702                     normalArray.push(y);
   703                     normalArray.push(z);
   705                     facemap[array[i]] = index++;
   706                 }
   708                 indexArray.push(facemap[array[i]]);
   709             }
   710         }
   711     }
   713     // set the VBOs
   714     obj.normalObject = obj.ctx.createBuffer();
   715     obj.ctx.bindBuffer(obj.ctx.ARRAY_BUFFER, obj.normalObject);
   716     obj.ctx.bufferData(obj.ctx.ARRAY_BUFFER, new Float32Array(normalArray), obj.ctx.STATIC_DRAW);
   718     obj.texCoordObject = obj.ctx.createBuffer();
   719     obj.ctx.bindBuffer(obj.ctx.ARRAY_BUFFER, obj.texCoordObject);
   720     obj.ctx.bufferData(obj.ctx.ARRAY_BUFFER, new Float32Array(textureArray), obj.ctx.STATIC_DRAW);
   722     obj.vertexObject = obj.ctx.createBuffer();
   723     obj.ctx.bindBuffer(obj.ctx.ARRAY_BUFFER, obj.vertexObject);
   724     obj.ctx.bufferData(obj.ctx.ARRAY_BUFFER, new Float32Array(vertexArray), obj.ctx.STATIC_DRAW);
   726     obj.numIndices = indexArray.length;
   727     obj.indexObject = obj.ctx.createBuffer();
   728     obj.ctx.bindBuffer(obj.ctx.ELEMENT_ARRAY_BUFFER, obj.indexObject);
   729     obj.ctx.bufferData(obj.ctx.ELEMENT_ARRAY_BUFFER, new Uint16Array(indexArray), obj.ctx.STREAM_DRAW);
   731     obj.loaded = true;
   732 }
   734 //
   735 // loadImageTexture
   736 //
   737 // Load the image at the passed url, place it in a new WebGLTexture object and return the WebGLTexture.
   738 //
   739 function loadImageTexture(ctx, url)
   740 {
   741     var texture = ctx.createTexture();
   742     texture.image = new Image();
   743     texture.image.onload = function() { doLoadImageTexture(ctx, texture.image, texture) }
   744     texture.image.src = url;
   745     return texture;
   746 }
   748 function doLoadImageTexture(ctx, image, texture)
   749 {
   750     ctx.enable(ctx.TEXTURE_2D);
   751     ctx.bindTexture(ctx.TEXTURE_2D, texture);
   752     ctx.texImage2D(ctx.TEXTURE_2D, 0, ctx.RGBA, ctx.RGBA, ctx.UNSIGNED_BYTE, image);
   753     ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_MAG_FILTER, ctx.LINEAR);
   754     ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_MIN_FILTER, ctx.LINEAR_MIPMAP_LINEAR);
   755     ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_WRAP_S, ctx.CLAMP_TO_EDGE);
   756     ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_WRAP_T, ctx.CLAMP_TO_EDGE);
   757     ctx.generateMipmap(ctx.TEXTURE_2D)
   758     ctx.bindTexture(ctx.TEXTURE_2D, 0);
   759 }
   761 //
   762 // Framerate object
   763 //
   764 // This object keeps track of framerate and displays it as the innerHTML text of the
   765 // HTML element with the passed id. Once created you call snapshot at the end
   766 // of every rendering cycle. Every 500ms the framerate is updated in the HTML element.
   767 //
   768 Framerate = function(id)
   769 {
   770     this.numFramerates = 10;
   771     this.framerateUpdateInterval = 500;
   772     this.id = id;
   774     this.renderTime = -1;
   775     this.framerates = [ ];
   776     self = this;
   777     var fr = function() { self.updateFramerate() }
   778     setInterval(fr, this.framerateUpdateInterval);
   779 }
   781 Framerate.prototype.updateFramerate = function()
   782 {
   783     var tot = 0;
   784     for (var i = 0; i < this.framerates.length; ++i)
   785         tot += this.framerates[i];
   787     var framerate = tot / this.framerates.length;
   788     framerate = Math.round(framerate);
   789     document.getElementById(this.id).innerHTML = "Framerate:"+framerate+"fps";
   790 }
   792 Framerate.prototype.snapshot = function()
   793 {
   794     if (this.renderTime < 0)
   795         this.renderTime = new Date().getTime();
   796     else {
   797         var newTime = new Date().getTime();
   798         var t = newTime - this.renderTime;
   799         var framerate = 1000/t;
   800         this.framerates.push(framerate);
   801         while (this.framerates.length > this.numFramerates)
   802             this.framerates.shift();
   803         this.renderTime = newTime;
   804     }
   805 }

mercurial