Index: conformance/resources/webgl-test.js |
=================================================================== |
--- conformance/resources/webgl-test.js (revision 0) |
+++ conformance/resources/webgl-test.js (revision 0) |
@@ -0,0 +1,788 @@ |
+/* |
+Copyright (C) 2011 Apple Computer, Inc. All rights reserved. |
+ |
+Redistribution and use in source and binary forms, with or without |
+modification, are permitted provided that the following conditions |
+are met: |
+1. Redistributions of source code must retain the above copyright |
+ notice, this list of conditions and the following disclaimer. |
+2. Redistributions in binary form must reproduce the above copyright |
+ notice, this list of conditions and the following disclaimer in the |
+ documentation and/or other materials provided with the distribution. |
+ |
+THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY |
+EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
+PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR |
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
+OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
+*/ |
+ |
+function webglTestLog(msg) { |
+ if (window.console && window.console.log) { |
+ window.console.log(msg); |
+ } |
+ if (document.getElementById("console")) { |
+ var log = document.getElementById("console"); |
+ log.innerHTML += msg + "<br>"; |
+ } |
+} |
+ |
+// |
+// create3DContext |
+// |
+// Returns the WebGLRenderingContext for any known implementation. |
+// |
+function create3DContext(canvas, attributes) |
+{ |
+ if (!canvas) |
+ canvas = document.createElement("canvas"); |
+ var context = null; |
+ try { |
+ context = canvas.getContext("webgl", attributes); |
+ } catch(e) {} |
+ if (!context) { |
+ try { |
+ context = canvas.getContext("experimental-webgl", attributes); |
+ } catch(e) {} |
+ } |
+ if (!context) { |
+ throw "Unable to fetch WebGL rendering context for Canvas"; |
+ } |
+ return context; |
+} |
+ |
+function createGLErrorWrapper(context, fname) { |
+ return function() { |
+ var rv = context[fname].apply(context, arguments); |
+ var err = context.getError(); |
+ if (err != 0) |
+ throw "GL error " + err + " in " + fname; |
+ return rv; |
+ }; |
+} |
+ |
+function create3DContextWithWrapperThatThrowsOnGLError(canvas, attributes) { |
+ var context = create3DContext(canvas, attributes); |
+ // Thanks to Ilmari Heikkinen for the idea on how to implement this so elegantly. |
+ var wrap = {}; |
+ for (var i in context) { |
+ try { |
+ if (typeof context[i] == 'function') { |
+ wrap[i] = createGLErrorWrapper(context, i); |
+ } else { |
+ wrap[i] = context[i]; |
+ } |
+ } catch (e) { |
+ webglTestLog("createContextWrapperThatThrowsOnGLError: Error accessing " + i); |
+ } |
+ } |
+ wrap.getError = function() { |
+ return context.getError(); |
+ }; |
+ return wrap; |
+} |
+ |
+function getGLErrorAsString(ctx, err) { |
+ if (err === ctx.NO_ERROR) { |
+ return "NO_ERROR"; |
+ } |
+ for (var name in ctx) { |
+ if (ctx[name] === err) { |
+ return name; |
+ } |
+ } |
+ return "0x" + err.toString(16); |
+} |
+ |
+// Pass undefined for glError to test that it at least throws some error |
+function shouldGenerateGLError(ctx, glErrors, evalStr) { |
+ if (!glErrors.length) { |
+ glErrors = [glErrors]; |
+ } |
+ var exception; |
+ try { |
+ eval(evalStr); |
+ } catch (e) { |
+ exception = e; |
+ } |
+ if (exception) { |
+ testFailed(evalStr + " threw exception " + exception); |
+ } else { |
+ var err = ctx.getError(); |
+ if (glErrors.indexOf(err) < 0) { |
+ var errStrs = []; |
+ for (var ii = 0; ii < glErrors.length; ++ii) { |
+ errStrs.push(getGLErrorAsString(ctx, glErrors[ii])); |
+ } |
+ testFailed(evalStr + " expected: " + errStrs.join(" or ") + ". Was " + getGLErrorAsString(ctx, err) + "."); |
+ } else { |
+ testPassed(evalStr + " generated expected GL error: " + getGLErrorAsString(ctx, err) + "."); |
+ } |
+ } |
+} |
+ |
+/** |
+ * Tests that the first error GL returns is the specified error. |
+ * @param {!WebGLContext} gl The WebGLContext to use. |
+ * @param {number} glError The expected gl error. |
+ * @param {string} opt_msg Optional additional message. |
+ */ |
+function glErrorShouldBe(gl, glError, opt_msg) { |
+ opt_msg = opt_msg || ""; |
+ var err = gl.getError(); |
+ if (err != glError) { |
+ testFailed("getError expected: " + getGLErrorAsString(gl, glError) + |
+ ". Was " + getGLErrorAsString(gl, err) + " : " + opt_msg); |
+ } else { |
+ testPassed("getError was expected value: " + |
+ getGLErrorAsString(gl, glError) + " : " + opt_msg); |
+ } |
+}; |
+ |
+// |
+// createProgram |
+// |
+// Create and return a program object, attaching each of the given shaders. |
+// |
+// If attribs are given, bind an attrib with that name at that index. |
+// |
+function createProgram(gl, vshaders, fshaders, attribs) |
+{ |
+ if (typeof(vshaders) == "string") |
+ vshaders = [vshaders]; |
+ if (typeof(fshaders) == "string") |
+ fshaders = [fshaders]; |
+ |
+ var shaders = []; |
+ var i; |
+ |
+ for (i = 0; i < vshaders.length; ++i) { |
+ var shader = loadShader(gl, vshaders[i], gl.VERTEX_SHADER); |
+ if (!shader) |
+ return null; |
+ shaders.push(shader); |
+ } |
+ |
+ for (i = 0; i < fshaders.length; ++i) { |
+ var shader = loadShader(gl, fshaders[i], gl.FRAGMENT_SHADER); |
+ if (!shader) |
+ return null; |
+ shaders.push(shader); |
+ } |
+ |
+ var prog = gl.createProgram(); |
+ for (i = 0; i < shaders.length; ++i) { |
+ gl.attachShader(prog, shaders[i]); |
+ } |
+ |
+ if (attribs) { |
+ for (var i in attribs) { |
+ gl.bindAttribLocation(prog, parseInt(i), attribs[i]); |
+ } |
+ } |
+ |
+ gl.linkProgram(prog); |
+ |
+ // Check the link status |
+ var linked = gl.getProgramParameter(prog, gl.LINK_STATUS); |
+ if (!linked) { |
+ // something went wrong with the link |
+ var error = gl.getProgramInfoLog(prog); |
+ webglTestLog("Error in program linking:" + error); |
+ |
+ gl.deleteProgram(prog); |
+ for (i = 0; i < shaders.length; ++i) |
+ gl.deleteShader(shaders[i]); |
+ return null; |
+ } |
+ |
+ return prog; |
+} |
+ |
+// |
+// initWebGL |
+// |
+// Initialize the Canvas element with the passed name as a WebGL object and return the |
+// WebGLRenderingContext. |
+// |
+// Load shaders with the passed names and create a program with them. Return this program |
+// in the 'program' property of the returned context. |
+// |
+// For each string in the passed attribs array, bind an attrib with that name at that index. |
+// Once the attribs are bound, link the program and then use it. |
+// |
+// Set the clear color to the passed array (4 values) and set the clear depth to the passed value. |
+// Enable depth testing and blending with a blend func of (SRC_ALPHA, ONE_MINUS_SRC_ALPHA) |
+// |
+function initWebGL(canvasName, vshader, fshader, attribs, clearColor, clearDepth, contextAttribs) |
+{ |
+ var canvas = document.getElementById(canvasName); |
+ var gl = create3DContext(canvas, contextAttribs); |
+ if (!gl) { |
+ alert("No WebGL context found"); |
+ return null; |
+ } |
+ |
+ // Create the program object |
+ gl.program = createProgram(gl, vshader, fshader, attribs); |
+ if (!gl.program) |
+ return null; |
+ |
+ gl.useProgram(gl.program); |
+ |
+ gl.clearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]); |
+ gl.clearDepth(clearDepth); |
+ |
+ gl.enable(gl.DEPTH_TEST); |
+ gl.enable(gl.BLEND); |
+ gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA); |
+ |
+ return gl; |
+} |
+ |
+// |
+// getShaderSource |
+// |
+// Load the source from the passed shader file. |
+// |
+function getShaderSource(file) |
+{ |
+ var xhr = new XMLHttpRequest(); |
+ xhr.open("GET", file, false); |
+ xhr.send(); |
+ return xhr.responseText; |
+} |
+ |
+ |
+// |
+// loadShader |
+// |
+// 'shader' is either the id of a <script> element containing the shader source |
+// string, the shader string itself, or the URL of a file containing the shader |
+// source. Load this shader and return the WebGLShader object corresponding to |
+// it. |
+// |
+function loadShader(ctx, shaderId, shaderType, isFile) |
+{ |
+ var shaderSource = ""; |
+ |
+ if (isFile) |
+ shaderSource = getShaderSource(shaderId); |
+ else { |
+ var shaderScript = document.getElementById(shaderId); |
+ if (!shaderScript) { |
+ shaderSource = shaderId; |
+ } else { |
+ if (shaderScript.type == "x-shader/x-vertex") { |
+ shaderType = ctx.VERTEX_SHADER; |
+ } else if (shaderScript.type == "x-shader/x-fragment") { |
+ shaderType = ctx.FRAGMENT_SHADER; |
+ } else if (shaderType != ctx.VERTEX_SHADER && shaderType != ctx.FRAGMENT_SHADER) { |
+ webglTestLog("*** Error: unknown shader type"); |
+ return null; |
+ } |
+ |
+ shaderSource = shaderScript.text; |
+ } |
+ } |
+ |
+ // Create the shader object |
+ var shader = ctx.createShader(shaderType); |
+ if (shader == null) { |
+ webglTestLog("*** Error: unable to create shader '"+shaderId+"'"); |
+ return null; |
+ } |
+ |
+ // Load the shader source |
+ ctx.shaderSource(shader, shaderSource); |
+ |
+ // Compile the shader |
+ ctx.compileShader(shader); |
+ |
+ // Check the compile status |
+ var compiled = ctx.getShaderParameter(shader, ctx.COMPILE_STATUS); |
+ if (!compiled) { |
+ // Something went wrong during compilation; get the error |
+ var error = ctx.getShaderInfoLog(shader); |
+ webglTestLog("*** Error compiling shader '"+shader+"':"+error); |
+ ctx.deleteShader(shader); |
+ return null; |
+ } |
+ |
+ return shader; |
+} |
+ |
+function loadShaderFromFile(ctx, file, type) |
+{ |
+ return loadShader(ctx, file, type, true); |
+} |
+ |
+function loadShaderFromScript(ctx, script) |
+{ |
+ return loadShader(ctx, script, 0, false); |
+} |
+ |
+function loadStandardProgram(context) { |
+ var program = context.createProgram(); |
+ context.attachShader(program, loadStandardVertexShader(context)); |
+ context.attachShader(program, loadStandardFragmentShader(context)); |
+ context.linkProgram(program); |
+ return program; |
+} |
+ |
+function loadProgram(context, vertexShaderPath, fragmentShaderPath, isFile) { |
+ isFile = (isFile === undefined) ? true : isFile; |
+ var program = context.createProgram(); |
+ context.attachShader(program, loadShader(context, vertexShaderPath, context.VERTEX_SHADER, isFile)); |
+ context.attachShader(program, loadShader(context, fragmentShaderPath, context.FRAGMENT_SHADER, isFile)); |
+ context.linkProgram(program); |
+ return program; |
+} |
+ |
+var getBasePathForResources = function() { |
+ var expectedBase = "webgl-test.js"; |
+ var scripts = document.getElementsByTagName('script'); |
+ for (var script, i = 0; script = scripts[i]; i++) { |
+ var src = script.src; |
+ var l = src.length; |
+ if (src.substr(l - expectedBase.length) == expectedBase) { |
+ return src.substr(0, l - expectedBase.length); |
+ } |
+ } |
+ throw 'oops'; |
+}; |
+ |
+ |
+function loadStandardVertexShader(context) { |
+ return loadShader( |
+ context, |
+ getBasePathForResources() + "vertexShader.vert", |
+ context.VERTEX_SHADER, |
+ true); |
+} |
+ |
+function loadStandardFragmentShader(context) { |
+ return loadShader( |
+ context, |
+ getBasePathForResources() + "fragmentShader.frag", |
+ context.FRAGMENT_SHADER, |
+ true); |
+} |
+ |
+// |
+// makeBox |
+// |
+// Create a box with vertices, normals and texCoords. Create VBOs for each as well as the index array. |
+// Return an object with the following properties: |
+// |
+// normalObject WebGLBuffer object for normals |
+// texCoordObject WebGLBuffer object for texCoords |
+// vertexObject WebGLBuffer object for vertices |
+// indexObject WebGLBuffer object for indices |
+// numIndices The number of indices in the indexObject |
+// |
+function makeBox(ctx) |
+{ |
+ // box |
+ // v6----- v5 |
+ // /| /| |
+ // v1------v0| |
+ // | | | | |
+ // | |v7---|-|v4 |
+ // |/ |/ |
+ // v2------v3 |
+ // |
+ // vertex coords array |
+ var vertices = new Float32Array( |
+ [ 1, 1, 1, -1, 1, 1, -1,-1, 1, 1,-1, 1, // v0-v1-v2-v3 front |
+ 1, 1, 1, 1,-1, 1, 1,-1,-1, 1, 1,-1, // v0-v3-v4-v5 right |
+ 1, 1, 1, 1, 1,-1, -1, 1,-1, -1, 1, 1, // v0-v5-v6-v1 top |
+ -1, 1, 1, -1, 1,-1, -1,-1,-1, -1,-1, 1, // v1-v6-v7-v2 left |
+ -1,-1,-1, 1,-1,-1, 1,-1, 1, -1,-1, 1, // v7-v4-v3-v2 bottom |
+ 1,-1,-1, -1,-1,-1, -1, 1,-1, 1, 1,-1 ] // v4-v7-v6-v5 back |
+ ); |
+ |
+ // normal array |
+ var normals = new Float32Array( |
+ [ 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, // v0-v1-v2-v3 front |
+ 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, // v0-v3-v4-v5 right |
+ 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, // v0-v5-v6-v1 top |
+ -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, // v1-v6-v7-v2 left |
+ 0,-1, 0, 0,-1, 0, 0,-1, 0, 0,-1, 0, // v7-v4-v3-v2 bottom |
+ 0, 0,-1, 0, 0,-1, 0, 0,-1, 0, 0,-1 ] // v4-v7-v6-v5 back |
+ ); |
+ |
+ |
+ // texCoord array |
+ var texCoords = new Float32Array( |
+ [ 1, 1, 0, 1, 0, 0, 1, 0, // v0-v1-v2-v3 front |
+ 0, 1, 0, 0, 1, 0, 1, 1, // v0-v3-v4-v5 right |
+ 1, 0, 1, 1, 0, 1, 0, 0, // v0-v5-v6-v1 top |
+ 1, 1, 0, 1, 0, 0, 1, 0, // v1-v6-v7-v2 left |
+ 0, 0, 1, 0, 1, 1, 0, 1, // v7-v4-v3-v2 bottom |
+ 0, 0, 1, 0, 1, 1, 0, 1 ] // v4-v7-v6-v5 back |
+ ); |
+ |
+ // index array |
+ var indices = new Uint8Array( |
+ [ 0, 1, 2, 0, 2, 3, // front |
+ 4, 5, 6, 4, 6, 7, // right |
+ 8, 9,10, 8,10,11, // top |
+ 12,13,14, 12,14,15, // left |
+ 16,17,18, 16,18,19, // bottom |
+ 20,21,22, 20,22,23 ] // back |
+ ); |
+ |
+ var retval = { }; |
+ |
+ retval.normalObject = ctx.createBuffer(); |
+ ctx.bindBuffer(ctx.ARRAY_BUFFER, retval.normalObject); |
+ ctx.bufferData(ctx.ARRAY_BUFFER, normals, ctx.STATIC_DRAW); |
+ |
+ retval.texCoordObject = ctx.createBuffer(); |
+ ctx.bindBuffer(ctx.ARRAY_BUFFER, retval.texCoordObject); |
+ ctx.bufferData(ctx.ARRAY_BUFFER, texCoords, ctx.STATIC_DRAW); |
+ |
+ retval.vertexObject = ctx.createBuffer(); |
+ ctx.bindBuffer(ctx.ARRAY_BUFFER, retval.vertexObject); |
+ ctx.bufferData(ctx.ARRAY_BUFFER, vertices, ctx.STATIC_DRAW); |
+ |
+ ctx.bindBuffer(ctx.ARRAY_BUFFER, 0); |
+ |
+ retval.indexObject = ctx.createBuffer(); |
+ ctx.bindBuffer(ctx.ELEMENT_ARRAY_BUFFER, retval.indexObject); |
+ ctx.bufferData(ctx.ELEMENT_ARRAY_BUFFER, indices, ctx.STATIC_DRAW); |
+ ctx.bindBuffer(ctx.ELEMENT_ARRAY_BUFFER, 0); |
+ |
+ retval.numIndices = indices.length; |
+ |
+ return retval; |
+} |
+ |
+// |
+// makeSphere |
+// |
+// Create a sphere with the passed number of latitude and longitude bands and the passed radius. |
+// Sphere has vertices, normals and texCoords. Create VBOs for each as well as the index array. |
+// Return an object with the following properties: |
+// |
+// normalObject WebGLBuffer object for normals |
+// texCoordObject WebGLBuffer object for texCoords |
+// vertexObject WebGLBuffer object for vertices |
+// indexObject WebGLBuffer object for indices |
+// numIndices The number of indices in the indexObject |
+// |
+function makeSphere(ctx, radius, lats, longs) |
+{ |
+ var geometryData = [ ]; |
+ var normalData = [ ]; |
+ var texCoordData = [ ]; |
+ var indexData = [ ]; |
+ |
+ for (var latNumber = 0; latNumber <= lats; ++latNumber) { |
+ for (var longNumber = 0; longNumber <= longs; ++longNumber) { |
+ var theta = latNumber * Math.PI / lats; |
+ var phi = longNumber * 2 * Math.PI / longs; |
+ var sinTheta = Math.sin(theta); |
+ var sinPhi = Math.sin(phi); |
+ var cosTheta = Math.cos(theta); |
+ var cosPhi = Math.cos(phi); |
+ |
+ var x = cosPhi * sinTheta; |
+ var y = cosTheta; |
+ var z = sinPhi * sinTheta; |
+ var u = 1-(longNumber/longs); |
+ var v = latNumber/lats; |
+ |
+ normalData.push(x); |
+ normalData.push(y); |
+ normalData.push(z); |
+ texCoordData.push(u); |
+ texCoordData.push(v); |
+ geometryData.push(radius * x); |
+ geometryData.push(radius * y); |
+ geometryData.push(radius * z); |
+ } |
+ } |
+ |
+ longs += 1; |
+ for (var latNumber = 0; latNumber < lats; ++latNumber) { |
+ for (var longNumber = 0; longNumber < longs; ++longNumber) { |
+ var first = (latNumber * longs) + (longNumber % longs); |
+ var second = first + longs; |
+ indexData.push(first); |
+ indexData.push(second); |
+ indexData.push(first+1); |
+ |
+ indexData.push(second); |
+ indexData.push(second+1); |
+ indexData.push(first+1); |
+ } |
+ } |
+ |
+ var retval = { }; |
+ |
+ retval.normalObject = ctx.createBuffer(); |
+ ctx.bindBuffer(ctx.ARRAY_BUFFER, retval.normalObject); |
+ ctx.bufferData(ctx.ARRAY_BUFFER, new Float32Array(normalData), ctx.STATIC_DRAW); |
+ |
+ retval.texCoordObject = ctx.createBuffer(); |
+ ctx.bindBuffer(ctx.ARRAY_BUFFER, retval.texCoordObject); |
+ ctx.bufferData(ctx.ARRAY_BUFFER, new Float32Array(texCoordData), ctx.STATIC_DRAW); |
+ |
+ retval.vertexObject = ctx.createBuffer(); |
+ ctx.bindBuffer(ctx.ARRAY_BUFFER, retval.vertexObject); |
+ ctx.bufferData(ctx.ARRAY_BUFFER, new Float32Array(geometryData), ctx.STATIC_DRAW); |
+ |
+ retval.numIndices = indexData.length; |
+ retval.indexObject = ctx.createBuffer(); |
+ ctx.bindBuffer(ctx.ELEMENT_ARRAY_BUFFER, retval.indexObject); |
+ ctx.bufferData(ctx.ELEMENT_ARRAY_BUFFER, new Uint16Array(indexData), ctx.STREAM_DRAW); |
+ |
+ return retval; |
+} |
+ |
+// |
+// loadObj |
+// |
+// Load a .obj file from the passed URL. Return an object with a 'loaded' property set to false. |
+// When the object load is complete, the 'loaded' property becomes true and the following |
+// properties are set: |
+// |
+// normalObject WebGLBuffer object for normals |
+// texCoordObject WebGLBuffer object for texCoords |
+// vertexObject WebGLBuffer object for vertices |
+// indexObject WebGLBuffer object for indices |
+// numIndices The number of indices in the indexObject |
+// |
+function loadObj(ctx, url) |
+{ |
+ var obj = { loaded : false }; |
+ obj.ctx = ctx; |
+ var req = new XMLHttpRequest(); |
+ req.obj = obj; |
+ req.onreadystatechange = function () { processLoadObj(req) }; |
+ req.open("GET", url, true); |
+ req.send(null); |
+ return obj; |
+} |
+ |
+function processLoadObj(req) |
+{ |
+ webglTestLog("req="+req) |
+ // only if req shows "complete" |
+ if (req.readyState == 4) { |
+ doLoadObj(req.obj, req.responseText); |
+ } |
+} |
+ |
+function doLoadObj(obj, text) |
+{ |
+ vertexArray = [ ]; |
+ normalArray = [ ]; |
+ textureArray = [ ]; |
+ indexArray = [ ]; |
+ |
+ var vertex = [ ]; |
+ var normal = [ ]; |
+ var texture = [ ]; |
+ var facemap = { }; |
+ var index = 0; |
+ |
+ var lines = text.split("\n"); |
+ for (var lineIndex in lines) { |
+ var line = lines[lineIndex].replace(/[ \t]+/g, " ").replace(/\s\s*$/, ""); |
+ |
+ // ignore comments |
+ if (line[0] == "#") |
+ continue; |
+ |
+ var array = line.split(" "); |
+ if (array[0] == "v") { |
+ // vertex |
+ vertex.push(parseFloat(array[1])); |
+ vertex.push(parseFloat(array[2])); |
+ vertex.push(parseFloat(array[3])); |
+ } |
+ else if (array[0] == "vt") { |
+ // normal |
+ texture.push(parseFloat(array[1])); |
+ texture.push(parseFloat(array[2])); |
+ } |
+ else if (array[0] == "vn") { |
+ // normal |
+ normal.push(parseFloat(array[1])); |
+ normal.push(parseFloat(array[2])); |
+ normal.push(parseFloat(array[3])); |
+ } |
+ else if (array[0] == "f") { |
+ // face |
+ if (array.length != 4) { |
+ webglTestLog("*** Error: face '"+line+"' not handled"); |
+ continue; |
+ } |
+ |
+ for (var i = 1; i < 4; ++i) { |
+ if (!(array[i] in facemap)) { |
+ // add a new entry to the map and arrays |
+ var f = array[i].split("/"); |
+ var vtx, nor, tex; |
+ |
+ if (f.length == 1) { |
+ vtx = parseInt(f[0]) - 1; |
+ nor = vtx; |
+ tex = vtx; |
+ } |
+ else if (f.length = 3) { |
+ vtx = parseInt(f[0]) - 1; |
+ tex = parseInt(f[1]) - 1; |
+ nor = parseInt(f[2]) - 1; |
+ } |
+ else { |
+ webglTestLog("*** Error: did not understand face '"+array[i]+"'"); |
+ return null; |
+ } |
+ |
+ // do the vertices |
+ var x = 0; |
+ var y = 0; |
+ var z = 0; |
+ if (vtx * 3 + 2 < vertex.length) { |
+ x = vertex[vtx*3]; |
+ y = vertex[vtx*3+1]; |
+ z = vertex[vtx*3+2]; |
+ } |
+ vertexArray.push(x); |
+ vertexArray.push(y); |
+ vertexArray.push(z); |
+ |
+ // do the textures |
+ x = 0; |
+ y = 0; |
+ if (tex * 2 + 1 < texture.length) { |
+ x = texture[tex*2]; |
+ y = texture[tex*2+1]; |
+ } |
+ textureArray.push(x); |
+ textureArray.push(y); |
+ |
+ // do the normals |
+ x = 0; |
+ y = 0; |
+ z = 1; |
+ if (nor * 3 + 2 < normal.length) { |
+ x = normal[nor*3]; |
+ y = normal[nor*3+1]; |
+ z = normal[nor*3+2]; |
+ } |
+ normalArray.push(x); |
+ normalArray.push(y); |
+ normalArray.push(z); |
+ |
+ facemap[array[i]] = index++; |
+ } |
+ |
+ indexArray.push(facemap[array[i]]); |
+ } |
+ } |
+ } |
+ |
+ // set the VBOs |
+ obj.normalObject = obj.ctx.createBuffer(); |
+ obj.ctx.bindBuffer(obj.ctx.ARRAY_BUFFER, obj.normalObject); |
+ obj.ctx.bufferData(obj.ctx.ARRAY_BUFFER, new Float32Array(normalArray), obj.ctx.STATIC_DRAW); |
+ |
+ obj.texCoordObject = obj.ctx.createBuffer(); |
+ obj.ctx.bindBuffer(obj.ctx.ARRAY_BUFFER, obj.texCoordObject); |
+ obj.ctx.bufferData(obj.ctx.ARRAY_BUFFER, new Float32Array(textureArray), obj.ctx.STATIC_DRAW); |
+ |
+ obj.vertexObject = obj.ctx.createBuffer(); |
+ obj.ctx.bindBuffer(obj.ctx.ARRAY_BUFFER, obj.vertexObject); |
+ obj.ctx.bufferData(obj.ctx.ARRAY_BUFFER, new Float32Array(vertexArray), obj.ctx.STATIC_DRAW); |
+ |
+ obj.numIndices = indexArray.length; |
+ obj.indexObject = obj.ctx.createBuffer(); |
+ obj.ctx.bindBuffer(obj.ctx.ELEMENT_ARRAY_BUFFER, obj.indexObject); |
+ obj.ctx.bufferData(obj.ctx.ELEMENT_ARRAY_BUFFER, new Uint16Array(indexArray), obj.ctx.STREAM_DRAW); |
+ |
+ obj.loaded = true; |
+} |
+ |
+// |
+// loadImageTexture |
+// |
+// Load the image at the passed url, place it in a new WebGLTexture object and return the WebGLTexture. |
+// |
+function loadImageTexture(ctx, url) |
+{ |
+ var texture = ctx.createTexture(); |
+ texture.image = new Image(); |
+ texture.image.onload = function() { doLoadImageTexture(ctx, texture.image, texture) } |
+ texture.image.src = url; |
+ return texture; |
+} |
+ |
+function doLoadImageTexture(ctx, image, texture) |
+{ |
+ ctx.enable(ctx.TEXTURE_2D); |
+ ctx.bindTexture(ctx.TEXTURE_2D, texture); |
+ ctx.texImage2D(ctx.TEXTURE_2D, 0, ctx.RGBA, ctx.RGBA, ctx.UNSIGNED_BYTE, image); |
+ ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_MAG_FILTER, ctx.LINEAR); |
+ ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_MIN_FILTER, ctx.LINEAR_MIPMAP_LINEAR); |
+ ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_WRAP_S, ctx.CLAMP_TO_EDGE); |
+ ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_WRAP_T, ctx.CLAMP_TO_EDGE); |
+ ctx.generateMipmap(ctx.TEXTURE_2D) |
+ ctx.bindTexture(ctx.TEXTURE_2D, 0); |
+} |
+ |
+// |
+// Framerate object |
+// |
+// This object keeps track of framerate and displays it as the innerHTML text of the |
+// HTML element with the passed id. Once created you call snapshot at the end |
+// of every rendering cycle. Every 500ms the framerate is updated in the HTML element. |
+// |
+Framerate = function(id) |
+{ |
+ this.numFramerates = 10; |
+ this.framerateUpdateInterval = 500; |
+ this.id = id; |
+ |
+ this.renderTime = -1; |
+ this.framerates = [ ]; |
+ self = this; |
+ var fr = function() { self.updateFramerate() } |
+ setInterval(fr, this.framerateUpdateInterval); |
+} |
+ |
+Framerate.prototype.updateFramerate = function() |
+{ |
+ var tot = 0; |
+ for (var i = 0; i < this.framerates.length; ++i) |
+ tot += this.framerates[i]; |
+ |
+ var framerate = tot / this.framerates.length; |
+ framerate = Math.round(framerate); |
+ document.getElementById(this.id).innerHTML = "Framerate:"+framerate+"fps"; |
+} |
+ |
+Framerate.prototype.snapshot = function() |
+{ |
+ if (this.renderTime < 0) |
+ this.renderTime = new Date().getTime(); |
+ else { |
+ var newTime = new Date().getTime(); |
+ var t = newTime - this.renderTime; |
+ var framerate = 1000/t; |
+ this.framerates.push(framerate); |
+ while (this.framerates.length > this.numFramerates) |
+ this.framerates.shift(); |
+ this.renderTime = newTime; |
+ } |
+} |
Property changes on: conformance/resources/webgl-test.js |
___________________________________________________________________ |
Added: svn:eol-style |
+ LF |